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. ¯\_(ツ)_/¯ |
| 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 |