OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 package datastore | |
6 | |
7 import ( | |
8 "fmt" | |
9 "reflect" | |
10 | |
11 "github.com/luci/luci-go/common/errors" | |
12 ) | |
13 | |
14 type multiArgType struct { | |
15 valid bool | |
16 | |
17 getKey func(nk newKeyFunc, slot reflect.Value) (Key, error) | |
18 getPM func(slot reflect.Value) (PropertyMap, error) | |
19 setPM func(slot reflect.Value, pm PropertyMap) error | |
20 setKey func(slot reflect.Value, k Key) | |
21 newElem func() reflect.Value | |
22 } | |
23 | |
24 func (mat *multiArgType) GetKeys(nk newKeyFunc, slice reflect.Value) ([]Key, err or) { | |
25 ret := make([]Key, slice.Len()) | |
26 lme := errors.LazyMultiError{Size: len(ret)} | |
27 for i := range ret { | |
28 key, err := mat.getKey(nk, slice.Index(i)) | |
29 lme.Assign(i, err) | |
30 ret[i] = key | |
31 } | |
32 return ret, lme.Get() | |
33 } | |
34 | |
35 func (mat *multiArgType) GetPMs(slice reflect.Value) ([]PropertyMap, error) { | |
36 ret := make([]PropertyMap, slice.Len()) | |
37 lme := errors.LazyMultiError{Size: len(ret)} | |
38 for i := range ret { | |
39 key, err := mat.getPM(slice.Index(i)) | |
40 lme.Assign(i, err) | |
41 ret[i] = key | |
42 } | |
43 return ret, lme.Get() | |
44 } | |
45 | |
46 // 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 | |
48 // type P such that P or *P implements PropertyLoadSaver. | |
49 func parseMultiArg(e reflect.Type) multiArgType { | |
50 if e.Kind() != reflect.Slice { | |
51 return multiArgTypeInvalid() | |
52 } | |
53 return parseArg(e.Elem()) | |
54 } | |
55 | |
56 // parseArg checks that et is of type S, *S, I, P or *P, for some | |
57 // struct type S, for some interface type I, or some non-interface non-pointer | |
58 // type P such that P or *P implements PropertyLoadSaver. | |
59 func parseArg(et reflect.Type) multiArgType { | |
60 if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) { | |
61 return multiArgTypePLS(et) | |
62 } | |
63 if et.Implements(typeOfPropertyLoadSaver) && et.Kind() != reflect.Interf ace { | |
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 return multiArgTypeInvalid() | |
78 } | |
79 | |
80 type newKeyFunc func(kind, sid string, iid int64, par Key) Key | |
81 | |
82 func multiArgTypeInvalid() multiArgType { | |
83 return multiArgType{} | |
84 } | |
85 | |
86 // multiArgTypePLS == []P | |
87 // *P implements PropertyLoadSaver | |
88 func multiArgTypePLS(et reflect.Type) multiArgType { | |
89 ret := multiArgType{ | |
90 valid: true, | |
91 | |
92 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
93 return newKeyObjErr(nk, slot.Addr().Interface()) | |
94 }, | |
95 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
96 return slot.Addr().Interface().(PropertyLoadSaver).Save( true) | |
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 setKey(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. ¯\_(ツ)_/¯ | |
Vadim Sh.
2015/08/03 21:25:12
:)
| |
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 valid: true, | |
127 | |
128 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
129 return newKeyObjErr(nk, slot.Interface()) | |
130 }, | |
131 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
132 return slot.Interface().(PropertyLoadSaver).Save(true) | |
133 }, | |
134 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
135 return slot.Interface().(PropertyLoadSaver).Load(pm) | |
136 }, | |
137 setKey: func(slot reflect.Value, k Key) { | |
138 setKey(slot.Interface(), k) | |
139 }, | |
140 } | |
141 if et.Kind() == reflect.Map { | |
142 ret.newElem = func() reflect.Value { | |
143 ptr := reflect.New(et) | |
144 ptr.Elem().Set(reflect.MakeMap(et)) | |
145 return ptr | |
146 } | |
147 } else { | |
148 ret.newElem = func() reflect.Value { return reflect.New(et) } | |
149 } | |
150 return ret | |
151 } | |
152 | |
153 // multiArgTypeStruct == []S | |
154 func multiArgTypeStruct(et reflect.Type) multiArgType { | |
155 cdc := getCodec(et) | |
156 if cdc.problem != nil { | |
157 return multiArgTypeInvalid() | |
158 } | |
159 toPLS := func(slot reflect.Value) PropertyLoadSaver { | |
160 return &structPLS{slot, cdc} | |
161 } | |
162 return multiArgType{ | |
163 valid: true, | |
164 | |
165 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
166 return newKeyObjErr(nk, toPLS(slot)) | |
167 }, | |
168 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
169 return toPLS(slot).(PropertyLoadSaver).Save(true) | |
170 }, | |
171 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
172 return toPLS(slot).(PropertyLoadSaver).Load(pm) | |
173 }, | |
174 setKey: func(slot reflect.Value, k Key) { | |
175 setKey(toPLS(slot), k) | |
176 }, | |
177 newElem: func() reflect.Value { | |
178 return reflect.New(et).Elem() | |
179 }, | |
180 } | |
181 } | |
182 | |
183 // multiArgTypeStructPtr == []*S | |
184 func multiArgTypeStructPtr(et reflect.Type) multiArgType { | |
185 cdc := getCodec(et) | |
186 if cdc.problem != nil { | |
187 return multiArgTypeInvalid() | |
188 } | |
189 toPLS := func(slot reflect.Value) PropertyLoadSaver { | |
190 return &structPLS{slot.Elem(), cdc} | |
191 } | |
192 return multiArgType{ | |
193 valid: true, | |
194 | |
195 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
196 return newKeyObjErr(nk, toPLS(slot)) | |
197 }, | |
198 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
199 return toPLS(slot).(PropertyLoadSaver).Save(true) | |
200 }, | |
201 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
202 return toPLS(slot).(PropertyLoadSaver).Load(pm) | |
203 }, | |
204 setKey: func(slot reflect.Value, k Key) { | |
205 setKey(toPLS(slot), k) | |
206 }, | |
207 newElem: func() reflect.Value { | |
208 return reflect.New(et) | |
209 }, | |
210 } | |
211 } | |
212 | |
213 // multiArgTypeInterface == []I | |
214 func multiArgTypeInterface() multiArgType { | |
215 return multiArgType{ | |
216 valid: true, | |
217 | |
218 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
219 return newKeyObjErr(nk, slot.Elem().Interface()) | |
220 }, | |
221 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
222 pls, _ := mkPLSName(slot.Elem().Interface()) | |
223 return pls.Save(true) | |
224 }, | |
225 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
226 pls, _ := mkPLSName(slot.Elem().Interface()) | |
227 return pls.Load(pm) | |
228 }, | |
229 setKey: func(slot reflect.Value, k Key) { | |
230 setKey(slot.Elem().Interface(), k) | |
231 }, | |
232 } | |
233 } | |
234 | |
235 func newKeyObjErr(nk newKeyFunc, src interface{}) (Key, error) { | |
236 pls, name := mkPLSName(src) | |
237 if key := getMetaKey(pls, "key"); key != nil { | |
238 return key, nil | |
239 } | |
240 | |
241 // get kind | |
242 kind := getMetaString(pls, "kind", name) | |
243 if kind == "" { | |
244 return nil, fmt.Errorf("unable to extract $kind from %v", src) | |
245 } | |
246 | |
247 // get id - allow both to be default for default keys | |
248 sid := getMetaString(pls, "id", "") | |
249 iid := getMetaInt64(pls, "id", 0) | |
250 | |
251 // get parent | |
252 par := getMetaKey(pls, "parent") | |
253 | |
254 return nk(kind, sid, iid, par), nil | |
255 } | |
256 | |
257 func setKey(src interface{}, key Key) { | |
258 pls, _ := mkPLSName(src) | |
259 if pls.SetMeta("key", key) == ErrMetaFieldUnset { | |
260 if key.StringID() != "" { | |
261 pls.SetMeta("id", key.StringID()) | |
262 } else { | |
263 pls.SetMeta("id", key.IntID()) | |
264 } | |
265 pls.SetMeta("kind", key.Kind()) | |
266 pls.SetMeta("parent", key.Parent()) | |
267 } | |
268 } | |
269 | |
270 func mkPLSName(o interface{}) (PropertyLoadSaver, string) { | |
271 if pls, ok := o.(*structPLS); ok { | |
272 return pls, pls.o.Type().Name() | |
273 } | |
274 if pls, ok := o.(PropertyLoadSaver); ok { | |
275 return pls, "" | |
276 } | |
277 pls := GetPLS(o) | |
278 name := pls.(*structPLS).o.Type().Name() | |
279 return pls, name | |
280 } | |
281 | |
282 func getMetaString(pls PropertyLoadSaver, key, dflt string) string { | |
283 mstr, err := pls.GetMeta(key) | |
284 ret, ok := mstr.(string) | |
285 if err != nil || !ok { | |
286 return dflt | |
287 } | |
288 return ret | |
289 } | |
290 | |
291 func getMetaInt64(pls PropertyLoadSaver, key string, dflt int64) int64 { | |
292 mint, err := pls.GetMeta(key) | |
293 ret, ok := mint.(int64) | |
294 if err != nil || !ok { | |
295 return dflt | |
296 } | |
297 return ret | |
298 } | |
299 | |
300 func getMetaKey(pls PropertyLoadSaver, key string) Key { | |
301 mkey, _ := pls.GetMeta(key) | |
302 ret, _ := mkey.(Key) | |
303 return ret | |
304 } | |
OLD | NEW |