Chromium Code Reviews| 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 |