OLD | NEW |
---|---|
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 } | |
OLD | NEW |