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

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: Update documentation and fix/clarify behavior on ExistsResult. Created 4 years, 6 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
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 //
27 » if meta { 27 // If allowKeys is true, a read-only key extraction multiArgType will be
28 » » getter = func(slot reflect.Value) (PropertyMap, error) { 28 // returned if et is a *Key.
29 » » » return mat.getMetaPM(slot), nil 29 func parseArg(et reflect.Type, keysOnly bool) *multiArgType {
iannucci 2016/05/28 02:50:53 s/keysOnly/allowKeys
dnj 2016/05/28 17:47:21 Done.
30 » if keysOnly && et == typeOfKey {
31 » » return multiArgTypeKeyExtraction()
32 » }
33
34 » if et.Kind() == reflect.Interface {
35 » » return multiArgTypeInterface()
36 » }
37
38 » // If a map type implements an interface, its pointer is also considered to
39 » // implement that interface.
40 » //
41 » // In this case, we have special pointer-to-map logic in multiArgTypePLS .
42 » if et.Implements(typeOfPropertyLoadSaver) {
43 » » return multiArgTypePLS(et)
44 » }
45 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
46 » » return multiArgTypePLSPtr(et)
47 » }
48
49 » switch et.Kind() {
50 » case reflect.Ptr:
51 » » if et.Elem().Kind() == reflect.Struct {
52 » » » return multiArgTypeStructPtr(et)
30 } 53 }
54
55 case reflect.Struct:
56 return multiArgTypeStruct(et)
31 } 57 }
32 » lme := errors.NewLazyMultiError(len(retKey)) 58
33 » for i := range retKey { 59 » 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 } 60 }
45 61
46 // parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some 62 // 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 63 // struct type S, for some interface type I, or some non-interface non-pointer
48 // type P such that P or *P implements PropertyLoadSaver. 64 // type P such that P or *P implements PropertyLoadSaver.
49 func parseMultiArg(e reflect.Type) multiArgType { 65 func mustParseMultiArg(et reflect.Type) *multiArgType {
50 » if e.Kind() != reflect.Slice { 66 » if et.Kind() != reflect.Slice {
51 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , e)) 67 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , et))
52 } 68 }
53 » return parseArg(e.Elem(), true) 69 » return mustParseArg(et.Elem())
54 } 70 }
55 71
56 // parseArg checks that et is of type S, *S, I, P or *P, for some 72 func mustParseArg(et reflect.Type) *multiArgType {
57 // struct type S, for some interface type I, or some non-interface non-pointer 73 » if mat := parseArg(et, false); mat != nil {
58 // type P such that P or *P implements PropertyLoadSaver. 74 » » return mat
59 func parseArg(et reflect.Type, multi bool) multiArgType {
60 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
61 » » return multiArgTypePLS(et)
62 } 75 }
63 » if et.Implements(typeOfPropertyLoadSaver) && et.Kind() != reflect.Interf ace { 76 » 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 } 77 }
82 78
83 type newKeyFunc func(kind, sid string, iid int64, par Key) Key 79 // multiArgTypePLS handles the case where et implements PropertyLoadSaver.
84 80 //
85 // multiArgTypePLS == []P 81 // This handles the special case of pointer-to-map (see parseArg).
86 // *P implements PropertyLoadSaver 82 func multiArgTypePLS(et reflect.Type) *multiArgType {
87 func multiArgTypePLS(et reflect.Type) multiArgType {
88 ret := multiArgType{ 83 ret := multiArgType{
89 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 84 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
90 » » » return newKeyObjErr(aid, ns, slot.Addr().Interface()) 85 » » » 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 }, 86 },
129 getPM: func(slot reflect.Value) (PropertyMap, error) { 87 getPM: func(slot reflect.Value) (PropertyMap, error) {
130 return slot.Interface().(PropertyLoadSaver).Save(true) 88 return slot.Interface().(PropertyLoadSaver).Save(true)
131 }, 89 },
132 getMetaPM: func(slot reflect.Value) PropertyMap { 90 getMetaPM: func(slot reflect.Value) PropertyMap {
133 return getMGS(slot.Interface()).GetAllMeta() 91 return getMGS(slot.Interface()).GetAllMeta()
134 }, 92 },
135 setPM: func(slot reflect.Value, pm PropertyMap) error { 93 setPM: func(slot reflect.Value, pm PropertyMap) error {
136 return slot.Interface().(PropertyLoadSaver).Load(pm) 94 return slot.Interface().(PropertyLoadSaver).Load(pm)
137 }, 95 },
138 setKey: func(slot reflect.Value, k *Key) { 96 setKey: func(slot reflect.Value, k *Key) {
139 PopulateKey(slot.Interface(), k) 97 PopulateKey(slot.Interface(), k)
140 }, 98 },
141 } 99 }
142 » if et.Kind() == reflect.Map { 100 » switch et.Kind() {
101 » case reflect.Map:
iannucci 2016/05/28 02:50:53 I think chans also can hit this.
dnj 2016/05/28 17:47:21 Done. Unfortunately, there is *no way* to communic
143 ret.newElem = func() reflect.Value { 102 ret.newElem = func() reflect.Value {
144 » » » ptr := reflect.New(et) 103 » » » return reflect.MakeMap(et)
145 » » » ptr.Elem().Set(reflect.MakeMap(et))
146 » » » return ptr
147 } 104 }
148 » } else { 105
149 » » ret.newElem = func() reflect.Value { return reflect.New(et) } 106 » case reflect.Ptr:
107 » » mapElem := et.Elem()
108 » » if mapElem.Kind() == reflect.Map {
109 » » » ret.newElem = func() reflect.Value {
110 » » » » ptr := reflect.New(mapElem)
111 » » » » ptr.Elem().Set(reflect.MakeMap(mapElem))
112 » » » » return ptr
113 » » » }
114 » » }
150 } 115 }
151 » return ret 116
117 » if ret.newElem == nil {
118 » » ret.newElem = func() reflect.Value {
119 » » » return reflect.New(et.Elem())
120 » » }
121 » }
122 » return &ret
123 }
124
125 // multiArgTypePLSPtr handles the case where et doesn't implement
126 // PropertyLoadSaver, but a pointer to et does.
127 func multiArgTypePLSPtr(et reflect.Type) *multiArgType {
128 » return &multiArgType{
129 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
130 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e()))
131 » » },
132 » » getPM: func(slot reflect.Value) (PropertyMap, error) {
133 » » » return slot.Addr().Interface().(PropertyLoadSaver).Save( true)
134 » » },
135 » » getMetaPM: func(slot reflect.Value) PropertyMap {
136 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
137 » » },
138 » » setPM: func(slot reflect.Value, pm PropertyMap) error {
139 » » » return slot.Addr().Interface().(PropertyLoadSaver).Load( pm)
140 » » },
141 » » setKey: func(slot reflect.Value, k *Key) {
142 » » » PopulateKey(slot.Addr().Interface(), k)
143 » » },
144 » » newElem: func() reflect.Value {
145 » » » return reflect.New(et).Elem()
146 » » },
147 » }
152 } 148 }
153 149
154 // multiArgTypeStruct == []S 150 // multiArgTypeStruct == []S
155 func multiArgTypeStruct(et reflect.Type) multiArgType { 151 func multiArgTypeStruct(et reflect.Type) *multiArgType {
156 cdc := getCodec(et) 152 cdc := getCodec(et)
157 toPLS := func(slot reflect.Value) *structPLS { 153 toPLS := func(slot reflect.Value) *structPLS {
158 return &structPLS{slot, cdc} 154 return &structPLS{slot, cdc}
159 } 155 }
160 » return multiArgType{ 156 » return &multiArgType{
161 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 157 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
162 » » » return newKeyObjErr(aid, ns, toPLS(slot)) 158 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e()))
163 }, 159 },
164 getPM: func(slot reflect.Value) (PropertyMap, error) { 160 getPM: func(slot reflect.Value) (PropertyMap, error) {
165 return toPLS(slot).Save(true) 161 return toPLS(slot).Save(true)
166 }, 162 },
167 getMetaPM: func(slot reflect.Value) PropertyMap { 163 getMetaPM: func(slot reflect.Value) PropertyMap {
168 » » » if slot.Type().Implements(typeOfMGS) { 164 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
169 » » » » return slot.Interface().(MetaGetterSetter).GetAl lMeta()
170 » » » }
171 » » » return toPLS(slot).GetAllMeta()
172 }, 165 },
173 setPM: func(slot reflect.Value, pm PropertyMap) error { 166 setPM: func(slot reflect.Value, pm PropertyMap) error {
174 return toPLS(slot).Load(pm) 167 return toPLS(slot).Load(pm)
175 }, 168 },
176 setKey: func(slot reflect.Value, k *Key) { 169 setKey: func(slot reflect.Value, k *Key) {
177 PopulateKey(toPLS(slot), k) 170 PopulateKey(toPLS(slot), k)
178 }, 171 },
179 newElem: func() reflect.Value { 172 newElem: func() reflect.Value {
180 return reflect.New(et).Elem() 173 return reflect.New(et).Elem()
181 }, 174 },
182 } 175 }
183 } 176 }
184 177
185 // multiArgTypeStructPtr == []*S 178 // multiArgTypeStructPtr == []*S
186 func multiArgTypeStructPtr(et reflect.Type) multiArgType { 179 func multiArgTypeStructPtr(et reflect.Type) *multiArgType {
187 » cdc := getCodec(et) 180 » cdc := getCodec(et.Elem())
188 toPLS := func(slot reflect.Value) *structPLS { 181 toPLS := func(slot reflect.Value) *structPLS {
189 return &structPLS{slot.Elem(), cdc} 182 return &structPLS{slot.Elem(), cdc}
190 } 183 }
191 » return multiArgType{ 184 » return &multiArgType{
192 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 185 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
193 » » » return newKeyObjErr(aid, ns, toPLS(slot)) 186 » » » return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
194 }, 187 },
195 getPM: func(slot reflect.Value) (PropertyMap, error) { 188 getPM: func(slot reflect.Value) (PropertyMap, error) {
196 return toPLS(slot).Save(true) 189 return toPLS(slot).Save(true)
197 }, 190 },
198 getMetaPM: func(slot reflect.Value) PropertyMap { 191 getMetaPM: func(slot reflect.Value) PropertyMap {
199 » » » if slot.Elem().Type().Implements(typeOfMGS) { 192 » » » return getMGS(slot.Interface()).GetAllMeta()
200 » » » » return getMGS(slot.Interface()).GetAllMeta()
201 » » » }
202 » » » return toPLS(slot).GetAllMeta()
203 }, 193 },
204 setPM: func(slot reflect.Value, pm PropertyMap) error { 194 setPM: func(slot reflect.Value, pm PropertyMap) error {
205 return toPLS(slot).Load(pm) 195 return toPLS(slot).Load(pm)
206 }, 196 },
207 setKey: func(slot reflect.Value, k *Key) { 197 setKey: func(slot reflect.Value, k *Key) {
208 PopulateKey(toPLS(slot), k) 198 PopulateKey(toPLS(slot), k)
209 }, 199 },
210 newElem: func() reflect.Value { 200 newElem: func() reflect.Value {
211 » » » return reflect.New(et) 201 » » » return reflect.New(et.Elem())
212 }, 202 },
213 } 203 }
214 } 204 }
215 205
216 // multiArgTypeInterface == []I 206 // multiArgTypeInterface == []I
217 func multiArgTypeInterface() multiArgType { 207 func multiArgTypeInterface() *multiArgType {
218 » return multiArgType{ 208 » return &multiArgType{
219 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 209 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
220 » » » return newKeyObjErr(aid, ns, slot.Elem().Interface()) 210 » » » return newKeyObjErr(aid, ns, getMGS(slot.Elem().Interfac e()))
221 }, 211 },
222 getPM: func(slot reflect.Value) (PropertyMap, error) { 212 getPM: func(slot reflect.Value) (PropertyMap, error) {
223 return mkPLS(slot.Elem().Interface()).Save(true) 213 return mkPLS(slot.Elem().Interface()).Save(true)
224 }, 214 },
225 getMetaPM: func(slot reflect.Value) PropertyMap { 215 getMetaPM: func(slot reflect.Value) PropertyMap {
226 return getMGS(slot.Elem().Interface()).GetAllMeta() 216 return getMGS(slot.Elem().Interface()).GetAllMeta()
227 }, 217 },
228 setPM: func(slot reflect.Value, pm PropertyMap) error { 218 setPM: func(slot reflect.Value, pm PropertyMap) error {
229 return mkPLS(slot.Elem().Interface()).Load(pm) 219 return mkPLS(slot.Elem().Interface()).Load(pm)
230 }, 220 },
231 setKey: func(slot reflect.Value, k *Key) { 221 setKey: func(slot reflect.Value, k *Key) {
232 PopulateKey(slot.Elem().Interface(), k) 222 PopulateKey(slot.Elem().Interface(), k)
233 }, 223 },
234 } 224 }
235 } 225 }
236 226
237 func newKeyObjErr(aid, ns string, src interface{}) (*Key, error) { 227 // multiArgTypeKeyExtraction == *Key
238 » pls := getMGS(src) 228 //
239 » if key, _ := GetMetaDefault(pls, "key", nil).(*Key); key != nil { 229 // This ONLY implements getKey.
230 func multiArgTypeKeyExtraction() *multiArgType {
231 » return &multiArgType{
232 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
233 » » » return slot.Interface().(*Key), nil
234 » » },
235 » }
236 }
237
238 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) {
239 » if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil {
240 return key, nil 240 return key, nil
241 } 241 }
242 242
243 // get kind 243 // get kind
244 » kind := GetMetaDefault(pls, "kind", "").(string) 244 » kind := GetMetaDefault(mgs, "kind", "").(string)
245 if kind == "" { 245 if kind == "" {
246 » » return nil, fmt.Errorf("unable to extract $kind from %T", src) 246 » » return nil, errors.New("unable to extract $kind")
247 } 247 }
248 248
249 // get id - allow both to be default for default keys 249 // get id - allow both to be default for default keys
250 » sid := GetMetaDefault(pls, "id", "").(string) 250 » sid := GetMetaDefault(mgs, "id", "").(string)
251 » iid := GetMetaDefault(pls, "id", 0).(int64) 251 » iid := GetMetaDefault(mgs, "id", 0).(int64)
252 252
253 // get parent 253 // get parent
254 » par, _ := GetMetaDefault(pls, "parent", nil).(*Key) 254 » par, _ := GetMetaDefault(mgs, "parent", nil).(*Key)
255 255
256 return NewKey(aid, ns, kind, sid, iid, par), nil 256 return NewKey(aid, ns, kind, sid, iid, par), nil
257 } 257 }
258 258
259 func mkPLS(o interface{}) PropertyLoadSaver { 259 func mkPLS(o interface{}) PropertyLoadSaver {
260 if pls, ok := o.(PropertyLoadSaver); ok { 260 if pls, ok := o.(PropertyLoadSaver); ok {
261 return pls 261 return pls
262 } 262 }
263 return GetPLS(o) 263 return GetPLS(o)
264 } 264 }
265
266 func isOKSingleType(t reflect.Type, allowKeys bool) error {
267 switch {
268 case t == nil:
269 return errors.New("no type information")
270 case t.Implements(typeOfPropertyLoadSaver):
271 return nil
272 case !allowKeys && t == typeOfKey:
273 return errors.New("not user datatype")
274 case t.Kind() != reflect.Ptr:
275 return errors.New("not a pointer")
276 case t.Elem().Kind() != reflect.Struct:
277 return errors.New("does not point to a struct")
278 default:
279 return nil
280 }
281 }
282
283 type metaMultiArgElement struct {
284 arg reflect.Value
285 mat *multiArgType
286 size int // size is -1 if this element is not a slice.
287 }
288
289 type metaMultiArg struct {
290 elems []metaMultiArgElement
291 keysOnly bool
292
293 count int // total number of elements, flattening slices
294 }
295
296 func makeMetaMultiArg(args []interface{}, keysOnly bool) (*metaMultiArg, error) {
297 mma := metaMultiArg{
298 elems: make([]metaMultiArgElement, len(args)),
299 keysOnly: keysOnly,
300 }
301
302 lme := errors.NewLazyMultiError(len(args))
303 for i, arg := range args {
304 if arg == nil {
305 lme.Assign(i, errors.New("cannot use nil as single argum ent"))
306 continue
307 }
308
309 v := reflect.ValueOf(arg)
310 vt := v.Type()
311 mma.elems[i].arg = v
312
313 // Try and treat the argument as a single-value first. This allo ws slices
314 // that implement PropertyLoadSaver to be properly treated as a single
315 // element.
316 var err error
317 isSlice := false
318 mat := parseArg(vt, keysOnly)
319 if mat == nil {
320 // If this is a slice, treat it as a slice of arg candid ates.
321 if v.Kind() == reflect.Slice {
322 isSlice = true
323 mat = parseArg(vt.Elem(), keysOnly)
324 }
325 } else {
326 // Single types need to be able to be assigned to.
327 err = isOKSingleType(vt, keysOnly)
328 }
329 if mat == nil {
330 err = errors.New("not a PLS or pointer-to-struct")
331 }
332 if err != nil {
333 lme.Assign(i, fmt.Errorf("invalid input type (%T): %s", arg, err))
334 continue
335 }
336
337 mma.elems[i].mat = mat
338 if isSlice {
339 l := v.Len()
340 mma.count += l
341 mma.elems[i].size = l
342 } else {
343 mma.count++
344 mma.elems[i].size = -1
345 }
346 }
347 if err := lme.Get(); err != nil {
348 return nil, err
349 }
350
351 return &mma, nil
352 }
353
354 func (mma *metaMultiArg) iterator(cb metaMultiArgIteratorCallback) *metaMultiArg Iterator {
355 return &metaMultiArgIterator{
356 metaMultiArg: mma,
357 cb: cb,
358 }
359 }
360
361 // getKeysPMs returns the
362 func (mma *metaMultiArg) getKeysPMs(aid, ns string, meta bool) ([]*Key, []Proper tyMap, error) {
363 var et errorTracker
364 it := mma.iterator(et.init(mma))
365
366 // Determine our flattened keys and property maps.
367 retKey := make([]*Key, mma.count)
368 var retPM []PropertyMap
369 if !mma.keysOnly {
370 retPM = make([]PropertyMap, mma.count)
371 }
372
373 for i := 0; i < mma.count; i++ {
374 it.next(func(mat *multiArgType, slot reflect.Value) error {
375 key, err := mat.getKey(aid, ns, slot)
376 if err != nil {
377 return err
378 }
379 retKey[i] = key
380
381 if !mma.keysOnly {
382 var pm PropertyMap
383 if meta {
384 pm = mat.getMetaPM(slot)
385 } else {
386 var err error
387 if pm, err = mat.getPM(slot); err != nil {
388 return err
389 }
390 }
391 retPM[i] = pm
392 }
393 return nil
394 })
395 }
396 return retKey, retPM, et.error()
397 }
398
399 type metaMultiArgIterator struct {
400 *metaMultiArg
401
402 cb metaMultiArgIteratorCallback
403
404 index int // flattened index
405 elemIdx int // current index in slice
406 slotIdx int // current index within elemIdx element (0 if single)
407 }
408
409 func (mac *metaMultiArgIterator) next(fn func(*multiArgType, reflect.Value) erro r) {
iannucci 2016/05/28 02:50:53 s/mac/it ?
dnj 2016/05/28 17:47:21 Done.
410 if mac.remaining() <= 0 {
411 panic("out of bounds")
412 }
413
414 // Advance to the next populated element/slot.
415 elem := &mac.elems[mac.elemIdx]
416 if mac.index > 0 {
417 for {
418 mac.slotIdx++
419 if mac.slotIdx >= elem.size {
420 mac.elemIdx++
421 mac.slotIdx = 0
422 elem = &mac.elems[mac.elemIdx]
423 }
424
425 // We're done iterating, unless we're on a zero-sized sl ice element.
426 if elem.size != 0 {
427 break
428 }
429 }
430 }
431
432 // Get the current slot value.
433 slot := elem.arg
434 if elem.size >= 0 {
435 // slot is a slice type, get its member.
436 slot = slot.Index(mac.slotIdx)
437 }
438
439 // Execute our callback.
440 mac.cb(mac, fn(elem.mat, slot))
441
442 // Advance our flattened index.
443 mac.index++
444 }
445
446 func (mac *metaMultiArgIterator) remaining() int {
447 return mac.count - mac.index
448 }
449
450 type metaMultiArgIteratorCallback func(*metaMultiArgIterator, error)
451
452 type errorTracker struct {
453 elemErrors errors.LazyMultiError
454 sliceErrors map[int]errors.LazyMultiError
455 }
456
457 func (et *errorTracker) init(mma *metaMultiArg) metaMultiArgIteratorCallback {
458 et.elemErrors = errors.NewLazyMultiError(len(mma.elems))
459 return et.trackError
460 }
461
462 func (et *errorTracker) trackError(it *metaMultiArgIterator, err error) {
463 if err == nil {
464 return
465 }
466
467 // If this is a single element, assign the error directly.
468 elem := it.elems[it.elemIdx]
469 if elem.size < 0 {
470 et.elemErrors.Assign(it.elemIdx, err)
471 } else {
472 // This is a slice element. Use a slice-sized MultiError for its element
473 // error slot, then add this error to the inner MultiError's slo t index.
474 ilme := et.sliceErrors[it.elemIdx]
475 if ilme == nil {
476 ilme = errors.NewLazyMultiError(elem.size)
477
478 if et.sliceErrors == nil {
479 et.sliceErrors = make(map[int]errors.LazyMultiEr ror)
iannucci 2016/05/28 02:50:53 let's just allocate the full 1st dimension map on
dnj 2016/05/28 17:47:21 Am building in-place. There is a bit of reflection
480 }
481 et.sliceErrors[it.elemIdx] = ilme
482 }
483 ilme.Assign(it.slotIdx, err)
484 }
485 }
486
487 func (et *errorTracker) error() error {
488 for i, lme := range et.sliceErrors {
489 if lerr := lme.Get(); lerr != nil {
490 et.elemErrors.Assign(i, lerr)
491 }
492 }
493 et.sliceErrors = nil
494 return et.elemErrors.Get()
495 }
496
497 type boolTracker struct {
498 errorTracker
499
500 res ExistsResult
501 }
502
503 func (bt *boolTracker) init(mma *metaMultiArg) metaMultiArgIteratorCallback {
504 bt.errorTracker.init(mma)
505
506 sizes := make([]int, len(mma.elems))
507 for i, e := range mma.elems {
508 if e.size < 0 {
509 sizes[i] = 1
510 } else {
511 sizes[i] = e.size
512 }
513 }
514
515 bt.res.init(sizes...)
516 return bt.trackExistsResult
517 }
518
519 func (bt *boolTracker) trackExistsResult(it *metaMultiArgIterator, err error) {
520 switch err {
521 case nil:
522 bt.res.set(it.elemIdx, it.slotIdx)
523
524 case ErrNoSuchEntity:
525 break
526
527 default:
528 // Pass through to track as MultiError.
529 bt.errorTracker.trackError(it, err)
530 }
531 }
532
533 func (bt *boolTracker) result() *ExistsResult {
534 bt.res.updateSlices()
535 return &bt.res
536 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698