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