Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: service/datastore/multiarg.go

Issue 2011773002: datastore: variadic Get, Put, Exists, Delete. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/gae@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package datastore 5 package datastore
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "reflect" 9 "reflect"
10 10
11 "github.com/luci/luci-go/common/errors" 11 "github.com/luci/luci-go/common/errors"
12 ) 12 )
13 13
14 type multiArgType struct { 14 type multiArgType struct {
15 getKey func(aid, ns string, slot reflect.Value) (*Key, error) 15 getKey func(aid, ns string, slot reflect.Value) (*Key, error)
16 getPM func(slot reflect.Value) (PropertyMap, error) 16 getPM func(slot reflect.Value) (PropertyMap, error)
17 getMetaPM func(slot reflect.Value) PropertyMap 17 getMetaPM func(slot reflect.Value) PropertyMap
18 setPM func(slot reflect.Value, pm PropertyMap) error 18 setPM func(slot reflect.Value, pm PropertyMap) error
19 setKey func(slot reflect.Value, k *Key) 19 setKey func(slot reflect.Value, k *Key)
20 newElem func() reflect.Value 20 newElem func() reflect.Value
21 } 21 }
22 22
23 func (mat *multiArgType) GetKeysPMs(aid, ns string, slice reflect.Value, meta bo ol) ([]*Key, []PropertyMap, error) { 23 // parseArg checks that et is of type S, *S, I, P or *P, for some
dnj 2016/05/25 05:27:16 This has been moved to the bottom, and is now a fu
24 » retKey := make([]*Key, slice.Len()) 24 // struct type S, for some interface type I, or some non-interface non-pointer
25 » retPM := make([]PropertyMap, slice.Len()) 25 // type P such that P or *P implements PropertyLoadSaver.
26 » getter := mat.getPM 26 func parseArg(et reflect.Type) *multiArgType {
27 » if meta { 27 » if et.Kind() == reflect.Interface {
28 » » getter = func(slot reflect.Value) (PropertyMap, error) { 28 » » return multiArgTypeInterface()
29 » » » return mat.getMetaPM(slot), nil 29 » }
30
31 » // If a map type implements an interface, its pointer is also considered to
dnj 2016/05/25 05:27:16 (This is why the map thing was so wonky. I didn't
32 » // implement that interface.
33 » //
34 » // In this case, we have special pointer-to-map logic in multiArgTypePLS .
35 » if et.Implements(typeOfPropertyLoadSaver) {
36 » » return multiArgTypePLS(et)
37 » }
38 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
39 » » return multiArgTypePLSPtr(et)
40 » }
41
42 » switch et.Kind() {
43 » case reflect.Ptr:
44 » » if et.Elem().Kind() == reflect.Struct {
45 » » » return multiArgTypeStructPtr(et)
30 } 46 }
47
48 case reflect.Struct:
49 return multiArgTypeStruct(et)
31 } 50 }
32 » lme := errors.NewLazyMultiError(len(retKey)) 51
33 » for i := range retKey { 52 » return nil
34 » » key, err := mat.getKey(aid, ns, slice.Index(i))
35 » » if !lme.Assign(i, err) {
36 » » » retKey[i] = key
37 » » » pm, err := getter(slice.Index(i))
38 » » » if !lme.Assign(i, err) {
39 » » » » retPM[i] = pm
40 » » » }
41 » » }
42 » }
43 » return retKey, retPM, lme.Get()
44 } 53 }
45 54
46 // parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some 55 // parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some
47 // struct type S, for some interface type I, or some non-interface non-pointer 56 // struct type S, for some interface type I, or some non-interface non-pointer
48 // type P such that P or *P implements PropertyLoadSaver. 57 // type P such that P or *P implements PropertyLoadSaver.
49 func parseMultiArg(e reflect.Type) multiArgType { 58 func mustParseMultiArg(et reflect.Type) *multiArgType {
50 » if e.Kind() != reflect.Slice { 59 » if et.Kind() != reflect.Slice {
51 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , e)) 60 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , et))
52 } 61 }
53 » return parseArg(e.Elem(), true) 62 » return mustParseArg(et.Elem())
54 } 63 }
55 64
56 // parseArg checks that et is of type S, *S, I, P or *P, for some 65 func mustParseArg(et reflect.Type) *multiArgType {
57 // struct type S, for some interface type I, or some non-interface non-pointer 66 » if mat := parseArg(et); mat != nil {
58 // type P such that P or *P implements PropertyLoadSaver. 67 » » return mat
59 func parseArg(et reflect.Type, multi bool) multiArgType {
60 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
61 » » return multiArgTypePLS(et)
62 } 68 }
63 » if et.Implements(typeOfPropertyLoadSaver) && et.Kind() != reflect.Interf ace { 69 » panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-s truct", et))
64 » » return multiArgTypePLSPtr(et.Elem())
65 » }
66 » switch et.Kind() {
67 » case reflect.Struct:
68 » » return multiArgTypeStruct(et)
69 » case reflect.Interface:
70 » » return multiArgTypeInterface()
71 » case reflect.Ptr:
72 » » et = et.Elem()
73 » » if et.Kind() == reflect.Struct {
74 » » » return multiArgTypeStructPtr(et)
75 » » }
76 » }
77 » if multi {
78 » » panic(fmt.Errorf("invalid argument type: []%s", et))
79 » }
80 » panic(fmt.Errorf("invalid argument type: %s", et))
81 } 70 }
82 71
83 type newKeyFunc func(kind, sid string, iid int64, par Key) Key 72 // multiArgTypePLS handles the case where et implements PropertyLoadSaver.
84 73 //
85 // multiArgTypePLS == []P 74 // This handles the special case of pointer-to-map (see parseArg).
86 // *P implements PropertyLoadSaver 75 func multiArgTypePLS(et reflect.Type) *multiArgType {
87 func multiArgTypePLS(et reflect.Type) multiArgType {
88 ret := multiArgType{ 76 ret := multiArgType{
89 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 77 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
90 » » » return newKeyObjErr(aid, ns, slot.Addr().Interface()) 78 » » » return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
91 » » },
92 » » getPM: func(slot reflect.Value) (PropertyMap, error) {
93 » » » return slot.Addr().Interface().(PropertyLoadSaver).Save( true)
94 » » },
95 » » getMetaPM: func(slot reflect.Value) PropertyMap {
96 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
97 » » },
98 » » setPM: func(slot reflect.Value, pm PropertyMap) error {
99 » » » return slot.Addr().Interface().(PropertyLoadSaver).Load( pm)
100 » » },
101 » » setKey: func(slot reflect.Value, k *Key) {
102 » » » PopulateKey(slot.Addr().Interface(), k)
103 » » },
104 » }
105 » if et.Kind() == reflect.Map {
106 » » ret.newElem = func() reflect.Value {
107 » » » // Create a *map so that way slot.Addr() works above whe n this is
108 » » » // called from Run(). Otherwise the map is 'unaddressabl e' according
109 » » » // to reflect. ¯\_(ツ)_/¯
110 » » » ptr := reflect.New(et)
111 » » » ptr.Elem().Set(reflect.MakeMap(et))
112 » » » return ptr.Elem()
113 » » }
114 » } else {
115 » » ret.newElem = func() reflect.Value {
116 » » » return reflect.New(et).Elem()
117 » » }
118 » }
119 » return ret
120 }
121
122 // multiArgTypePLSPtr == []*P
123 // *P implements PropertyLoadSaver
124 func multiArgTypePLSPtr(et reflect.Type) multiArgType {
125 » ret := multiArgType{
126 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
127 » » » return newKeyObjErr(aid, ns, slot.Interface())
128 }, 79 },
129 getPM: func(slot reflect.Value) (PropertyMap, error) { 80 getPM: func(slot reflect.Value) (PropertyMap, error) {
130 return slot.Interface().(PropertyLoadSaver).Save(true) 81 return slot.Interface().(PropertyLoadSaver).Save(true)
131 }, 82 },
132 getMetaPM: func(slot reflect.Value) PropertyMap { 83 getMetaPM: func(slot reflect.Value) PropertyMap {
133 return getMGS(slot.Interface()).GetAllMeta() 84 return getMGS(slot.Interface()).GetAllMeta()
134 }, 85 },
135 setPM: func(slot reflect.Value, pm PropertyMap) error { 86 setPM: func(slot reflect.Value, pm PropertyMap) error {
136 return slot.Interface().(PropertyLoadSaver).Load(pm) 87 return slot.Interface().(PropertyLoadSaver).Load(pm)
137 }, 88 },
138 setKey: func(slot reflect.Value, k *Key) { 89 setKey: func(slot reflect.Value, k *Key) {
139 PopulateKey(slot.Interface(), k) 90 PopulateKey(slot.Interface(), k)
140 }, 91 },
141 } 92 }
142 » if et.Kind() == reflect.Map { 93 » switch et.Kind() {
94 » case reflect.Map:
143 ret.newElem = func() reflect.Value { 95 ret.newElem = func() reflect.Value {
144 » » » ptr := reflect.New(et) 96 » » » return reflect.MakeMap(et)
145 » » » ptr.Elem().Set(reflect.MakeMap(et))
146 » » » return ptr
147 } 97 }
148 » } else { 98
149 » » ret.newElem = func() reflect.Value { return reflect.New(et) } 99 » case reflect.Ptr:
100 » » mapElem := et.Elem()
101 » » if mapElem.Kind() == reflect.Map {
102 » » » ret.newElem = func() reflect.Value {
103 » » » » ptr := reflect.New(mapElem)
104 » » » » ptr.Elem().Set(reflect.MakeMap(mapElem))
105 » » » » return ptr
106 » » » }
107 » » }
150 } 108 }
151 » return ret 109
110 » if ret.newElem == nil {
111 » » ret.newElem = func() reflect.Value {
112 » » » return reflect.New(et.Elem())
113 » » }
114 » }
115 » return &ret
116 }
117
118 // multiArgTypePLSPtr handles the case where et doesn't implement
119 // PropertyLoadSaver, but a pointer to et does.
120 func multiArgTypePLSPtr(et reflect.Type) *multiArgType {
121 » return &multiArgType{
122 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
123 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e()))
124 » » },
125 » » getPM: func(slot reflect.Value) (PropertyMap, error) {
126 » » » return slot.Addr().Interface().(PropertyLoadSaver).Save( true)
127 » » },
128 » » getMetaPM: func(slot reflect.Value) PropertyMap {
129 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
130 » » },
131 » » setPM: func(slot reflect.Value, pm PropertyMap) error {
132 » » » return slot.Addr().Interface().(PropertyLoadSaver).Load( pm)
133 » » },
134 » » setKey: func(slot reflect.Value, k *Key) {
135 » » » PopulateKey(slot.Addr().Interface(), k)
136 » » },
137 » » newElem: func() reflect.Value {
138 » » » return reflect.New(et).Elem()
139 » » },
140 » }
152 } 141 }
153 142
154 // multiArgTypeStruct == []S 143 // multiArgTypeStruct == []S
155 func multiArgTypeStruct(et reflect.Type) multiArgType { 144 func multiArgTypeStruct(et reflect.Type) *multiArgType {
156 cdc := getCodec(et) 145 cdc := getCodec(et)
157 toPLS := func(slot reflect.Value) *structPLS { 146 toPLS := func(slot reflect.Value) *structPLS {
158 return &structPLS{slot, cdc} 147 return &structPLS{slot, cdc}
159 } 148 }
160 » return multiArgType{ 149 » return &multiArgType{
161 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 150 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
162 » » » return newKeyObjErr(aid, ns, toPLS(slot)) 151 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e()))
dnj 2016/05/25 05:27:16 This was a bug. MGS overrides wouldn't be honored.
163 }, 152 },
164 getPM: func(slot reflect.Value) (PropertyMap, error) { 153 getPM: func(slot reflect.Value) (PropertyMap, error) {
165 return toPLS(slot).Save(true) 154 return toPLS(slot).Save(true)
166 }, 155 },
167 getMetaPM: func(slot reflect.Value) PropertyMap { 156 getMetaPM: func(slot reflect.Value) PropertyMap {
168 » » » if slot.Type().Implements(typeOfMGS) { 157 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
169 » » » » return slot.Interface().(MetaGetterSetter).GetAl lMeta()
170 » » » }
171 » » » return toPLS(slot).GetAllMeta()
172 }, 158 },
173 setPM: func(slot reflect.Value, pm PropertyMap) error { 159 setPM: func(slot reflect.Value, pm PropertyMap) error {
174 return toPLS(slot).Load(pm) 160 return toPLS(slot).Load(pm)
175 }, 161 },
176 setKey: func(slot reflect.Value, k *Key) { 162 setKey: func(slot reflect.Value, k *Key) {
177 PopulateKey(toPLS(slot), k) 163 PopulateKey(toPLS(slot), k)
178 }, 164 },
179 newElem: func() reflect.Value { 165 newElem: func() reflect.Value {
180 return reflect.New(et).Elem() 166 return reflect.New(et).Elem()
181 }, 167 },
182 } 168 }
183 } 169 }
184 170
185 // multiArgTypeStructPtr == []*S 171 // multiArgTypeStructPtr == []*S
186 func multiArgTypeStructPtr(et reflect.Type) multiArgType { 172 func multiArgTypeStructPtr(et reflect.Type) *multiArgType {
187 » cdc := getCodec(et) 173 » cdc := getCodec(et.Elem())
188 toPLS := func(slot reflect.Value) *structPLS { 174 toPLS := func(slot reflect.Value) *structPLS {
189 return &structPLS{slot.Elem(), cdc} 175 return &structPLS{slot.Elem(), cdc}
190 } 176 }
191 » return multiArgType{ 177 » return &multiArgType{
192 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 178 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
193 » » » return newKeyObjErr(aid, ns, toPLS(slot)) 179 » » » return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
194 }, 180 },
195 getPM: func(slot reflect.Value) (PropertyMap, error) { 181 getPM: func(slot reflect.Value) (PropertyMap, error) {
196 return toPLS(slot).Save(true) 182 return toPLS(slot).Save(true)
197 }, 183 },
198 getMetaPM: func(slot reflect.Value) PropertyMap { 184 getMetaPM: func(slot reflect.Value) PropertyMap {
199 » » » if slot.Elem().Type().Implements(typeOfMGS) { 185 » » » return getMGS(slot.Interface()).GetAllMeta()
200 » » » » return getMGS(slot.Interface()).GetAllMeta()
201 » » » }
202 » » » return toPLS(slot).GetAllMeta()
203 }, 186 },
204 setPM: func(slot reflect.Value, pm PropertyMap) error { 187 setPM: func(slot reflect.Value, pm PropertyMap) error {
205 » » » return toPLS(slot).Load(pm) 188 » » » err := toPLS(slot).Load(pm)
dnj 2016/05/25 05:27:16 I'll collapse this in the next PS.
189 » » » return err
206 }, 190 },
207 setKey: func(slot reflect.Value, k *Key) { 191 setKey: func(slot reflect.Value, k *Key) {
208 PopulateKey(toPLS(slot), k) 192 PopulateKey(toPLS(slot), k)
209 }, 193 },
210 newElem: func() reflect.Value { 194 newElem: func() reflect.Value {
211 » » » return reflect.New(et) 195 » » » return reflect.New(et.Elem())
212 }, 196 },
213 } 197 }
214 } 198 }
215 199
216 // multiArgTypeInterface == []I 200 // multiArgTypeInterface == []I
217 func multiArgTypeInterface() multiArgType { 201 func multiArgTypeInterface() *multiArgType {
218 » return multiArgType{ 202 » return &multiArgType{
219 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 203 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
220 » » » return newKeyObjErr(aid, ns, slot.Elem().Interface()) 204 » » » return newKeyObjErr(aid, ns, getMGS(slot.Elem().Interfac e()))
dnj 2016/05/25 05:27:16 This, I think, was a bug.
221 }, 205 },
222 getPM: func(slot reflect.Value) (PropertyMap, error) { 206 getPM: func(slot reflect.Value) (PropertyMap, error) {
223 return mkPLS(slot.Elem().Interface()).Save(true) 207 return mkPLS(slot.Elem().Interface()).Save(true)
224 }, 208 },
225 getMetaPM: func(slot reflect.Value) PropertyMap { 209 getMetaPM: func(slot reflect.Value) PropertyMap {
226 return getMGS(slot.Elem().Interface()).GetAllMeta() 210 return getMGS(slot.Elem().Interface()).GetAllMeta()
227 }, 211 },
228 setPM: func(slot reflect.Value, pm PropertyMap) error { 212 setPM: func(slot reflect.Value, pm PropertyMap) error {
229 return mkPLS(slot.Elem().Interface()).Load(pm) 213 return mkPLS(slot.Elem().Interface()).Load(pm)
230 }, 214 },
231 setKey: func(slot reflect.Value, k *Key) { 215 setKey: func(slot reflect.Value, k *Key) {
232 PopulateKey(slot.Elem().Interface(), k) 216 PopulateKey(slot.Elem().Interface(), k)
233 }, 217 },
234 } 218 }
235 } 219 }
236 220
237 func newKeyObjErr(aid, ns string, src interface{}) (*Key, error) { 221 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) {
238 » pls := getMGS(src) 222 » if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil {
239 » if key, _ := GetMetaDefault(pls, "key", nil).(*Key); key != nil {
240 return key, nil 223 return key, nil
241 } 224 }
242 225
243 // get kind 226 // get kind
244 » kind := GetMetaDefault(pls, "kind", "").(string) 227 » kind := GetMetaDefault(mgs, "kind", "").(string)
245 if kind == "" { 228 if kind == "" {
246 » » return nil, fmt.Errorf("unable to extract $kind from %T", src) 229 » » return nil, errors.New("unable to extract $kind")
247 } 230 }
248 231
249 // get id - allow both to be default for default keys 232 // get id - allow both to be default for default keys
250 » sid := GetMetaDefault(pls, "id", "").(string) 233 » sid := GetMetaDefault(mgs, "id", "").(string)
251 » iid := GetMetaDefault(pls, "id", 0).(int64) 234 » iid := GetMetaDefault(mgs, "id", 0).(int64)
252 235
253 // get parent 236 // get parent
254 » par, _ := GetMetaDefault(pls, "parent", nil).(*Key) 237 » par, _ := GetMetaDefault(mgs, "parent", nil).(*Key)
255 238
256 return NewKey(aid, ns, kind, sid, iid, par), nil 239 return NewKey(aid, ns, kind, sid, iid, par), nil
257 } 240 }
258 241
259 func mkPLS(o interface{}) PropertyLoadSaver { 242 func mkPLS(o interface{}) PropertyLoadSaver {
260 if pls, ok := o.(PropertyLoadSaver); ok { 243 if pls, ok := o.(PropertyLoadSaver); ok {
261 return pls 244 return pls
262 } 245 }
263 return GetPLS(o) 246 return GetPLS(o)
264 } 247 }
248
249 func isOKSingleType(t reflect.Type) error {
250 if t == nil {
251 return errors.New("no type information")
252 }
253 if t.Implements(typeOfPropertyLoadSaver) {
254 return nil
255 }
256 if t == typeOfKey {
257 return errors.New("not user datatype")
258 }
259 if t.Kind() != reflect.Ptr {
260 return errors.New("not a pointer")
261 }
262 if t.Elem().Kind() != reflect.Struct {
263 return errors.New("does not point to a struct")
264 }
265 return nil
266 }
267
268 type metaMultiArgElement struct {
269 arg reflect.Value
270 mat *multiArgType
271 size int // size is -1 if this element is not a slice.
272 }
273
274 type metaMultiArg struct {
dnj 2016/05/25 05:27:16 *so meta* But if there's a better name I might be
275 elems []metaMultiArgElement
276
277 count int // total number of elements, flattening slices
278 }
279
280 func makeMetaMultiArg(args []interface{}) (*metaMultiArg, error) {
281 mma := metaMultiArg{
282 elems: make([]metaMultiArgElement, len(args)),
283 }
284
285 lme := errors.NewLazyMultiError(len(args))
286 for i, arg := range args {
287 if arg == nil {
288 lme.Assign(i, errors.New("cannot use nil as single argum ent"))
289 continue
290 }
291
292 v := reflect.ValueOf(arg)
293 vt := v.Type()
294 mma.elems[i].arg = v
295
296 // Try and treat the argument as a single-value first. This allo ws slices
297 // that implement PropertyLoadSaver to be properly treated as a single
298 // element.
299 var err error
300 isSlice := false
301 mat := parseArg(vt)
302 if mat == nil {
303 // If this is a slice, treat it as a slice of arg candid ates.
304 if v.Kind() == reflect.Slice {
305 isSlice = true
306 mat = parseArg(vt.Elem())
307 }
308 } else {
309 // Single types need to be able to be assigned to.
310 err = isOKSingleType(vt)
311 }
312 if mat == nil {
313 err = errors.New("not a PLS or pointer-to-struct")
314 }
315 if err != nil {
316 lme.Assign(i, fmt.Errorf("invalid input type (%T): %s", arg, err))
317 continue
318 }
319
320 mma.elems[i].mat = mat
321 if isSlice {
322 l := v.Len()
323 mma.count += l
324 mma.elems[i].size = l
325 } else {
326 mma.count++
327 mma.elems[i].size = -1
328 }
329 }
330 if err := lme.Get(); err != nil {
331 return nil, err
332 }
333
334 return &mma, nil
335 }
336
337 func (mma *metaMultiArg) iterator() *metaMultiArgIterator {
338 return &metaMultiArgIterator{
339 metaMultiArg: mma,
340
341 elemErrors: errors.NewLazyMultiError(len(mma.elems)),
342 }
343 }
344
345 // getKeysPMs returns the
346 func (mma *metaMultiArg) getKeysPMs(aid, ns string, meta bool) ([]*Key, []Proper tyMap, error) {
347 it := mma.iterator()
348
349 // Determine our flattened keys and property maps.
350 retKey := make([]*Key, mma.count)
351 retPM := make([]PropertyMap, mma.count)
352
353 for i := 0; i < mma.count; i++ {
354 it.next(func(mat *multiArgType, slot reflect.Value) error {
355 key, err := mat.getKey(aid, ns, slot)
356 if err != nil {
357 return err
358 }
359 retKey[i] = key
360
361 var pm PropertyMap
362 if meta {
363 pm = mat.getMetaPM(slot)
364 } else {
365 var err error
366 if pm, err = mat.getPM(slot); err != nil {
367 return err
368 }
369 }
370 retPM[i] = pm
371 return nil
372 })
373 }
374 return retKey, retPM, it.error()
375 }
376
377 type metaMultiArgIterator struct {
378 *metaMultiArg
379
380 elemErrors errors.LazyMultiError
381 sliceErrors map[int]errors.LazyMultiError
382
383 index int // flattened index
384 elemIdx int // current index in slice
385 slotIdx int // current index within elemIdx element (0 if single)
386 }
387
388 func (mac *metaMultiArgIterator) next(fn func(*multiArgType, reflect.Value) erro r) {
389 if mac.remaining() <= 0 {
390 panic("out of bounds")
391 }
392
393 // Get the current element and slot.
394 elem := &mac.elems[mac.elemIdx]
395
396 // Get the current slot value.
397 slot := elem.arg
398 if elem.size >= 0 {
399 // slot is a slice type, get its member.
400 slot = slot.Index(mac.slotIdx)
401 }
402
403 // Execute our callback.
404 if err := fn(elem.mat, slot); err != nil {
405 // If this is a single element, assign the error directly.
406 if elem.size < 0 {
407 mac.elemErrors.Assign(mac.elemIdx, err)
408 } else {
409 // This is a slice element. Use a slice-sized MultiError for its element
410 // error slot, then add this error to the inner MultiErr or's slot index.
411 ilme := mac.sliceErrors[mac.elemIdx]
412 if ilme == nil {
413 ilme = errors.NewLazyMultiError(elem.size)
414
415 if mac.sliceErrors == nil {
416 mac.sliceErrors = make(map[int]errors.La zyMultiError)
417 }
418 mac.sliceErrors[mac.elemIdx] = ilme
419 }
420 ilme.Assign(mac.slotIdx, err)
421 }
422 }
423
424 // Advance to the next element/slot.
425 mac.index++
426 mac.slotIdx++
427 if mac.slotIdx >= elem.size {
428 mac.elemIdx++
429 mac.slotIdx = 0
430 }
431 }
432
433 func (mac *metaMultiArgIterator) error() error {
434 lme := errors.NewLazyMultiError(len(mac.elems))
435 for i, elem := range mac.elems {
436 if elem.size < 0 {
437 lme.Assign(i, mac.elemErrors.GetOne(i))
438 } else {
439 if serr := mac.sliceErrors[i]; serr != nil {
440 lme.Assign(i, serr.Get())
441 }
442 }
443 }
444 return lme.Get()
445 }
446
447 func (mac *metaMultiArgIterator) remaining() int {
448 return mac.count - mac.index
449 }
OLDNEW
« service/datastore/interface.go ('K') | « service/datastore/interface.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698