text: package request
  
  import (
  	"reflect"
  	"sync/atomic"
  
  	"github.com/aws/aws-sdk-go/aws"
  	"github.com/aws/aws-sdk-go/aws/awsutil"
  )
  
  // A Pagination provides paginating of SDK API operations which are paginatable.
  // Generally you should not use this type directly, but use the "Pages" API
  // operations method to automatically perform pagination for you. Such as,
  // "S3.ListObjectsPages", and "S3.ListObjectsPagesWithContext" methods.
  //
  // Pagination differs from a Paginator type in that pagination is the type that
  // does the pagination between API operations, and Paginator defines the
  // configuration that will be used per page request.
  //
  //     for p.Next() {
  //         data := p.Page().(*s3.ListObjectsOutput)
  //         // process the page's data
  //         // ...
  //         // break out of loop to stop fetching additional pages
  //     }
  //
  //     return p.Err()
  //
  // See service client API operation Pages methods for examples how the SDK will
  // use the Pagination type.
  type Pagination struct {
  	// Function to return a Request value for each pagination request.
  	// Any configuration or handlers that need to be applied to the request
  	// prior to getting the next page should be done here before the request
  	// returned.
  	//
  	// NewRequest should always be built from the same API operations. It is
  	// undefined if different API operations are returned on subsequent calls.
  	NewRequest func() (*Request, error)
  	// EndPageOnSameToken, when enabled, will allow the paginator to stop on
  	// token that are the same as its previous tokens.
  	EndPageOnSameToken bool
  
  	started    bool
  	prevTokens []interface{}
  	nextTokens []interface{}
  
  	err     error
  	curPage interface{}
  }
  
  // HasNextPage will return true if Pagination is able to determine that the API
  // operation has additional pages. False will be returned if there are no more
  // pages remaining.
  //
  // Will always return true if Next has not been called yet.
  func (p *Pagination) HasNextPage() bool {
  	if !p.started {
  		return true
  	}
  
  	hasNextPage := len(p.nextTokens) != 0
  	if p.EndPageOnSameToken {
  		return hasNextPage && !awsutil.DeepEqual(p.nextTokens, p.prevTokens)
  	}
  	return hasNextPage
  }
  
  // Err returns the error Pagination encountered when retrieving the next page.
  func (p *Pagination) Err() error {
  	return p.err
  }
  
  // Page returns the current page. Page should only be called after a successful
  // call to Next. It is undefined what Page will return if Page is called after
  // Next returns false.
  func (p *Pagination) Page() interface{} {
  	return p.curPage
  }
  
  // Next will attempt to retrieve the next page for the API operation. When a page
  // is retrieved true will be returned. If the page cannot be retrieved, or there
  // are no more pages false will be returned.
  //
  // Use the Page method to retrieve the current page data. The data will need
  // to be cast to the API operation's output type.
  //
  // Use the Err method to determine if an error occurred if Page returns false.
  func (p *Pagination) Next() bool {
  	if !p.HasNextPage() {
  		return false
  	}
  
  	req, err := p.NewRequest()
  	if err != nil {
  		p.err = err
  		return false
  	}
  
  	if p.started {
  		for i, intok := range req.Operation.InputTokens {
  			awsutil.SetValueAtPath(req.Params, intok, p.nextTokens[i])
  		}
  	}
  	p.started = true
  
  	err = req.Send()
  	if err != nil {
  		p.err = err
  		return false
  	}
  
  	p.prevTokens = p.nextTokens
  	p.nextTokens = req.nextPageTokens()
  	p.curPage = req.Data
  
  	return true
  }
  
  // A Paginator is the configuration data that defines how an API operation
  // should be paginated. This type is used by the API service models to define
  // the generated pagination config for service APIs.
  //
  // The Pagination type is what provides iterating between pages of an API. It
  // is only used to store the token metadata the SDK should use for performing
  // pagination.
  type Paginator struct {
  	InputTokens     []string
  	OutputTokens    []string
  	LimitToken      string
  	TruncationToken string
  }
  
  // nextPageTokens returns the tokens to use when asking for the next page of data.
  func (r *Request) nextPageTokens() []interface{} {
  	if r.Operation.Paginator == nil {
  		return nil
  	}
  	if r.Operation.TruncationToken != "" {
  		tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken)
  		if len(tr) == 0 {
  			return nil
  		}
  
  		switch v := tr[0].(type) {
  		case *bool:
  			if !aws.BoolValue(v) {
  				return nil
  			}
  		case bool:
  			if !v {
  				return nil
  			}
  		}
  	}
  
  	tokens := []interface{}{}
  	tokenAdded := false
  	for _, outToken := range r.Operation.OutputTokens {
  		vs, _ := awsutil.ValuesAtPath(r.Data, outToken)
  		if len(vs) == 0 {
  			tokens = append(tokens, nil)
  			continue
  		}
  		v := vs[0]
  
  		switch tv := v.(type) {
  		case *string:
  			if len(aws.StringValue(tv)) == 0 {
  				tokens = append(tokens, nil)
  				continue
  			}
  		case string:
  			if len(tv) == 0 {
  				tokens = append(tokens, nil)
  				continue
  			}
  		}
  
  		tokenAdded = true
  		tokens = append(tokens, v)
  	}
  	if !tokenAdded {
  		return nil
  	}
  
  	return tokens
  }
  
  // Ensure a deprecated item is only logged once instead of each time its used.
  func logDeprecatedf(logger aws.Logger, flag *int32, msg string) {
  	if logger == nil {
  		return
  	}
  	if atomic.CompareAndSwapInt32(flag, 0, 1) {
  		logger.Log(msg)
  	}
  }
  
  var (
  	logDeprecatedHasNextPage int32
  	logDeprecatedNextPage    int32
  	logDeprecatedEachPage    int32
  )
  
  // HasNextPage returns true if this request has more pages of data available.
  //
  // Deprecated Use Pagination type for configurable pagination of API operations
  func (r *Request) HasNextPage() bool {
  	logDeprecatedf(r.Config.Logger, &logDeprecatedHasNextPage,
  		"Request.HasNextPage deprecated. Use Pagination type for configurable pagination of API operations")
  
  	return len(r.nextPageTokens()) > 0
  }
  
  // NextPage returns a new Request that can be executed to return the next
  // page of result data. Call .Send() on this request to execute it.
  //
  // Deprecated Use Pagination type for configurable pagination of API operations
  func (r *Request) NextPage() *Request {
  	logDeprecatedf(r.Config.Logger, &logDeprecatedNextPage,
  		"Request.NextPage deprecated. Use Pagination type for configurable pagination of API operations")
  
  	tokens := r.nextPageTokens()
  	if len(tokens) == 0 {
  		return nil
  	}
  
  	data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
  	nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
  	for i, intok := range nr.Operation.InputTokens {
  		awsutil.SetValueAtPath(nr.Params, intok, tokens[i])
  	}
  	return nr
  }
  
  // EachPage iterates over each page of a paginated request object. The fn
  // parameter should be a function with the following sample signature:
  //
  //   func(page *T, lastPage bool) bool {
  //       return true // return false to stop iterating
  //   }
  //
  // Where "T" is the structure type matching the output structure of the given
  // operation. For example, a request object generated by
  // DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
  // as the structure "T". The lastPage value represents whether the page is
  // the last page of data or not. The return value of this function should
  // return true to keep iterating or false to stop.
  //
  // Deprecated Use Pagination type for configurable pagination of API operations
  func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
  	logDeprecatedf(r.Config.Logger, &logDeprecatedEachPage,
  		"Request.EachPage deprecated. Use Pagination type for configurable pagination of API operations")
  
  	for page := r; page != nil; page = page.NextPage() {
  		if err := page.Send(); err != nil {
  			return err
  		}
  		if getNextPage := fn(page.Data, !page.HasNextPage()); !getNextPage {
  			return page.Error
  		}
  	}
  
  	return nil
  }
  