diff options
Diffstat (limited to 'vendor/google.golang.org/api/iterator/iterator.go')
-rw-r--r-- | vendor/google.golang.org/api/iterator/iterator.go | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/vendor/google.golang.org/api/iterator/iterator.go b/vendor/google.golang.org/api/iterator/iterator.go new file mode 100644 index 0000000..3c8ea77 --- /dev/null +++ b/vendor/google.golang.org/api/iterator/iterator.go | |||
@@ -0,0 +1,231 @@ | |||
1 | // Copyright 2016 Google LLC | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | |||
15 | // Package iterator provides support for standard Google API iterators. | ||
16 | // See https://github.com/GoogleCloudPlatform/gcloud-golang/wiki/Iterator-Guidelines. | ||
17 | package iterator | ||
18 | |||
19 | import ( | ||
20 | "errors" | ||
21 | "fmt" | ||
22 | "reflect" | ||
23 | ) | ||
24 | |||
25 | // Done is returned by an iterator's Next method when the iteration is | ||
26 | // complete; when there are no more items to return. | ||
27 | var Done = errors.New("no more items in iterator") | ||
28 | |||
29 | // We don't support mixed calls to Next and NextPage because they play | ||
30 | // with the paging state in incompatible ways. | ||
31 | var errMixed = errors.New("iterator: Next and NextPage called on same iterator") | ||
32 | |||
33 | // PageInfo contains information about an iterator's paging state. | ||
34 | type PageInfo struct { | ||
35 | // Token is the token used to retrieve the next page of items from the | ||
36 | // API. You may set Token immediately after creating an iterator to | ||
37 | // begin iteration at a particular point. If Token is the empty string, | ||
38 | // the iterator will begin with the first eligible item. | ||
39 | // | ||
40 | // The result of setting Token after the first call to Next is undefined. | ||
41 | // | ||
42 | // After the underlying API method is called to retrieve a page of items, | ||
43 | // Token is set to the next-page token in the response. | ||
44 | Token string | ||
45 | |||
46 | // MaxSize is the maximum number of items returned by a call to the API. | ||
47 | // Set MaxSize as a hint to optimize the buffering behavior of the iterator. | ||
48 | // If zero, the page size is determined by the underlying service. | ||
49 | // | ||
50 | // Use Pager to retrieve a page of a specific, exact size. | ||
51 | MaxSize int | ||
52 | |||
53 | // The error state of the iterator. Manipulated by PageInfo.next and Pager. | ||
54 | // This is a latch: it starts as nil, and once set should never change. | ||
55 | err error | ||
56 | |||
57 | // If true, no more calls to fetch should be made. Set to true when fetch | ||
58 | // returns an empty page token. The iterator is Done when this is true AND | ||
59 | // the buffer is empty. | ||
60 | atEnd bool | ||
61 | |||
62 | // Function that fetches a page from the underlying service. It should pass | ||
63 | // the pageSize and pageToken arguments to the service, fill the buffer | ||
64 | // with the results from the call, and return the next-page token returned | ||
65 | // by the service. The function must not remove any existing items from the | ||
66 | // buffer. If the underlying RPC takes an int32 page size, pageSize should | ||
67 | // be silently truncated. | ||
68 | fetch func(pageSize int, pageToken string) (nextPageToken string, err error) | ||
69 | |||
70 | // Function that returns the number of currently buffered items. | ||
71 | bufLen func() int | ||
72 | |||
73 | // Function that returns the buffer, after setting the buffer variable to nil. | ||
74 | takeBuf func() interface{} | ||
75 | |||
76 | // Set to true on first call to PageInfo.next or Pager.NextPage. Used to check | ||
77 | // for calls to both Next and NextPage with the same iterator. | ||
78 | nextCalled, nextPageCalled bool | ||
79 | } | ||
80 | |||
81 | // NewPageInfo exposes internals for iterator implementations. | ||
82 | // It is not a stable interface. | ||
83 | var NewPageInfo = newPageInfo | ||
84 | |||
85 | // If an iterator can support paging, its iterator-creating method should call | ||
86 | // this (via the NewPageInfo variable above). | ||
87 | // | ||
88 | // The fetch, bufLen and takeBuf arguments provide access to the | ||
89 | // iterator's internal slice of buffered items. They behave as described in | ||
90 | // PageInfo, above. | ||
91 | // | ||
92 | // The return value is the PageInfo.next method bound to the returned PageInfo value. | ||
93 | // (Returning it avoids exporting PageInfo.next.) | ||
94 | func newPageInfo(fetch func(int, string) (string, error), bufLen func() int, takeBuf func() interface{}) (*PageInfo, func() error) { | ||
95 | pi := &PageInfo{ | ||
96 | fetch: fetch, | ||
97 | bufLen: bufLen, | ||
98 | takeBuf: takeBuf, | ||
99 | } | ||
100 | return pi, pi.next | ||
101 | } | ||
102 | |||
103 | // Remaining returns the number of items available before the iterator makes another API call. | ||
104 | func (pi *PageInfo) Remaining() int { return pi.bufLen() } | ||
105 | |||
106 | // next provides support for an iterator's Next function. An iterator's Next | ||
107 | // should return the error returned by next if non-nil; else it can assume | ||
108 | // there is at least one item in its buffer, and it should return that item and | ||
109 | // remove it from the buffer. | ||
110 | func (pi *PageInfo) next() error { | ||
111 | pi.nextCalled = true | ||
112 | if pi.err != nil { // Once we get an error, always return it. | ||
113 | // TODO(jba): fix so users can retry on transient errors? Probably not worth it. | ||
114 | return pi.err | ||
115 | } | ||
116 | if pi.nextPageCalled { | ||
117 | pi.err = errMixed | ||
118 | return pi.err | ||
119 | } | ||
120 | // Loop until we get some items or reach the end. | ||
121 | for pi.bufLen() == 0 && !pi.atEnd { | ||
122 | if err := pi.fill(pi.MaxSize); err != nil { | ||
123 | pi.err = err | ||
124 | return pi.err | ||
125 | } | ||
126 | if pi.Token == "" { | ||
127 | pi.atEnd = true | ||
128 | } | ||
129 | } | ||
130 | // Either the buffer is non-empty or pi.atEnd is true (or both). | ||
131 | if pi.bufLen() == 0 { | ||
132 | // The buffer is empty and pi.atEnd is true, i.e. the service has no | ||
133 | // more items. | ||
134 | pi.err = Done | ||
135 | } | ||
136 | return pi.err | ||
137 | } | ||
138 | |||
139 | // Call the service to fill the buffer, using size and pi.Token. Set pi.Token to the | ||
140 | // next-page token returned by the call. | ||
141 | // If fill returns a non-nil error, the buffer will be empty. | ||
142 | func (pi *PageInfo) fill(size int) error { | ||
143 | tok, err := pi.fetch(size, pi.Token) | ||
144 | if err != nil { | ||
145 | pi.takeBuf() // clear the buffer | ||
146 | return err | ||
147 | } | ||
148 | pi.Token = tok | ||
149 | return nil | ||
150 | } | ||
151 | |||
152 | // Pageable is implemented by iterators that support paging. | ||
153 | type Pageable interface { | ||
154 | // PageInfo returns paging information associated with the iterator. | ||
155 | PageInfo() *PageInfo | ||
156 | } | ||
157 | |||
158 | // Pager supports retrieving iterator items a page at a time. | ||
159 | type Pager struct { | ||
160 | pageInfo *PageInfo | ||
161 | pageSize int | ||
162 | } | ||
163 | |||
164 | // NewPager returns a pager that uses iter. Calls to its NextPage method will | ||
165 | // obtain exactly pageSize items, unless fewer remain. The pageToken argument | ||
166 | // indicates where to start the iteration. Pass the empty string to start at | ||
167 | // the beginning, or pass a token retrieved from a call to Pager.NextPage. | ||
168 | // | ||
169 | // If you use an iterator with a Pager, you must not call Next on the iterator. | ||
170 | func NewPager(iter Pageable, pageSize int, pageToken string) *Pager { | ||
171 | p := &Pager{ | ||
172 | pageInfo: iter.PageInfo(), | ||
173 | pageSize: pageSize, | ||
174 | } | ||
175 | p.pageInfo.Token = pageToken | ||
176 | if pageSize <= 0 { | ||
177 | p.pageInfo.err = errors.New("iterator: page size must be positive") | ||
178 | } | ||
179 | return p | ||
180 | } | ||
181 | |||
182 | // NextPage retrieves a sequence of items from the iterator and appends them | ||
183 | // to slicep, which must be a pointer to a slice of the iterator's item type. | ||
184 | // Exactly p.pageSize items will be appended, unless fewer remain. | ||
185 | // | ||
186 | // The first return value is the page token to use for the next page of items. | ||
187 | // If empty, there are no more pages. Aside from checking for the end of the | ||
188 | // iteration, the returned page token is only needed if the iteration is to be | ||
189 | // resumed a later time, in another context (possibly another process). | ||
190 | // | ||
191 | // The second return value is non-nil if an error occurred. It will never be | ||
192 | // the special iterator sentinel value Done. To recognize the end of the | ||
193 | // iteration, compare nextPageToken to the empty string. | ||
194 | // | ||
195 | // It is possible for NextPage to return a single zero-length page along with | ||
196 | // an empty page token when there are no more items in the iteration. | ||
197 | func (p *Pager) NextPage(slicep interface{}) (nextPageToken string, err error) { | ||
198 | p.pageInfo.nextPageCalled = true | ||
199 | if p.pageInfo.err != nil { | ||
200 | return "", p.pageInfo.err | ||
201 | } | ||
202 | if p.pageInfo.nextCalled { | ||
203 | p.pageInfo.err = errMixed | ||
204 | return "", p.pageInfo.err | ||
205 | } | ||
206 | if p.pageInfo.bufLen() > 0 { | ||
207 | return "", errors.New("must call NextPage with an empty buffer") | ||
208 | } | ||
209 | // The buffer must be empty here, so takeBuf is a no-op. We call it just to get | ||
210 | // the buffer's type. | ||
211 | wantSliceType := reflect.PtrTo(reflect.ValueOf(p.pageInfo.takeBuf()).Type()) | ||
212 | if slicep == nil { | ||
213 | return "", errors.New("nil passed to Pager.NextPage") | ||
214 | } | ||
215 | vslicep := reflect.ValueOf(slicep) | ||
216 | if vslicep.Type() != wantSliceType { | ||
217 | return "", fmt.Errorf("slicep should be of type %s, got %T", wantSliceType, slicep) | ||
218 | } | ||
219 | for p.pageInfo.bufLen() < p.pageSize { | ||
220 | if err := p.pageInfo.fill(p.pageSize - p.pageInfo.bufLen()); err != nil { | ||
221 | p.pageInfo.err = err | ||
222 | return "", p.pageInfo.err | ||
223 | } | ||
224 | if p.pageInfo.Token == "" { | ||
225 | break | ||
226 | } | ||
227 | } | ||
228 | e := vslicep.Elem() | ||
229 | e.Set(reflect.AppendSlice(e, reflect.ValueOf(p.pageInfo.takeBuf()))) | ||
230 | return p.pageInfo.Token, nil | ||
231 | } | ||