Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
|
Vadim Sh.
2015/07/29 16:21:43
I miss templates :)
iannucci
2015/08/03 03:56:32
Yeah me too :)
| |
| 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 switch et.Kind() { | |
| 64 case reflect.Struct: | |
| 65 return multiArgTypeStruct(et) | |
| 66 case reflect.Interface: | |
| 67 return multiArgTypeInterface() | |
| 68 case reflect.Ptr: | |
| 69 et = et.Elem() | |
| 70 switch et.Kind() { | |
| 71 case reflect.Ptr: | |
| 72 return multiArgTypePLSPtr(et) | |
| 73 case 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 return reflect.MakeMap(et) | |
| 108 } | |
| 109 } else { | |
| 110 ret.newElem = func() reflect.Value { | |
| 111 return reflect.New(et).Elem() | |
| 112 } | |
| 113 } | |
| 114 return ret | |
| 115 } | |
| 116 | |
| 117 // multiArgTypePLSPtr == []*P | |
| 118 // *P implements PropertyLoadSaver | |
| 119 func multiArgTypePLSPtr(et reflect.Type) multiArgType { | |
| 120 ret := multiArgType{ | |
| 121 valid: true, | |
| 122 | |
| 123 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
| 124 return newKeyObjErr(nk, slot.Interface()) | |
| 125 }, | |
| 126 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 127 return slot.Interface().(PropertyLoadSaver).Save(true) | |
| 128 }, | |
| 129 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 130 return slot.Interface().(PropertyLoadSaver).Load(pm) | |
| 131 }, | |
| 132 setKey: func(slot reflect.Value, k Key) { | |
| 133 setKey(slot.Interface(), k) | |
| 134 }, | |
| 135 } | |
| 136 e := et.Elem() | |
| 137 if e.Kind() == reflect.Map { | |
| 138 ret.newElem = func() reflect.Value { | |
| 139 ptr := reflect.New(e) | |
| 140 ptr.Elem().Set(reflect.MakeMap(e)) | |
| 141 return ptr | |
| 142 } | |
| 143 } else { | |
| 144 ret.newElem = func() reflect.Value { return reflect.New(e) } | |
| 145 } | |
| 146 return ret | |
| 147 } | |
| 148 | |
| 149 // multiArgTypeStruct == []S | |
| 150 func multiArgTypeStruct(et reflect.Type) multiArgType { | |
| 151 cdc := getCodec(et) | |
| 152 toPLS := func(slot reflect.Value) PropertyLoadSaver { | |
| 153 return &structPLS{slot, cdc} | |
| 154 } | |
| 155 return multiArgType{ | |
| 156 valid: true, | |
| 157 | |
| 158 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
| 159 return newKeyObjErr(nk, toPLS(slot)) | |
| 160 }, | |
| 161 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 162 return toPLS(slot).(PropertyLoadSaver).Save(true) | |
| 163 }, | |
| 164 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 165 return toPLS(slot).(PropertyLoadSaver).Load(pm) | |
| 166 }, | |
| 167 setKey: func(slot reflect.Value, k Key) { | |
| 168 setKey(toPLS(slot), k) | |
| 169 }, | |
| 170 newElem: func() reflect.Value { | |
| 171 return reflect.New(et).Elem() | |
| 172 }, | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 // multiArgTypeStructPtr == []*S | |
| 177 func multiArgTypeStructPtr(et reflect.Type) multiArgType { | |
| 178 cdc := getCodec(et.Elem()) | |
| 179 toPLS := func(slot reflect.Value) PropertyLoadSaver { | |
| 180 return &structPLS{slot.Elem(), cdc} | |
| 181 } | |
| 182 return multiArgType{ | |
| 183 valid: true, | |
| 184 | |
| 185 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
| 186 return newKeyObjErr(nk, toPLS(slot)) | |
| 187 }, | |
| 188 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 189 return toPLS(slot).(PropertyLoadSaver).Save(true) | |
| 190 }, | |
| 191 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 192 return toPLS(slot).(PropertyLoadSaver).Load(pm) | |
| 193 }, | |
| 194 setKey: func(slot reflect.Value, k Key) { | |
| 195 setKey(toPLS(slot), k) | |
| 196 }, | |
| 197 newElem: func() reflect.Value { | |
| 198 return reflect.New(et).Elem() | |
| 199 }, | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 // multiArgTypeInterface == []I | |
| 204 func multiArgTypeInterface() multiArgType { | |
| 205 return multiArgType{ | |
| 206 valid: true, | |
| 207 | |
| 208 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) { | |
| 209 return newKeyObjErr(nk, slot.Interface()) | |
| 210 }, | |
| 211 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 212 pls, _ := mkPLSName(slot.Interface()) | |
| 213 return pls.Save(true) | |
| 214 }, | |
| 215 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 216 pls, _ := mkPLSName(slot.Interface()) | |
| 217 return pls.Load(pm) | |
| 218 }, | |
| 219 setKey: func(slot reflect.Value, k Key) { | |
| 220 setKey(slot.Interface(), k) | |
| 221 }, | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 func newKeyObjErr(nk newKeyFunc, src interface{}) (Key, error) { | |
| 226 pls, name := mkPLSName(src) | |
| 227 if key := getMetaKey(pls, "key"); key != nil { | |
| 228 return key, nil | |
| 229 } | |
| 230 | |
| 231 // get kind | |
| 232 kind := getMetaString(pls, "kind", name) | |
| 233 if kind == "" { | |
| 234 return nil, fmt.Errorf("unable to extract $kind from %v", src) | |
| 235 } | |
| 236 | |
| 237 // get id - allow both to be default for default keys | |
| 238 sid := getMetaString(pls, "id", "") | |
| 239 iid := getMetaInt64(pls, "id", 0) | |
| 240 | |
| 241 // get parent | |
| 242 par := getMetaKey(pls, "parent") | |
| 243 | |
| 244 return nk(kind, sid, iid, par), nil | |
| 245 } | |
| 246 | |
| 247 func setKey(src interface{}, key Key) { | |
| 248 pls, _ := mkPLSName(src) | |
| 249 if pls.SetMeta("key", key) == ErrMetaFieldUnset { | |
| 250 if key.StringID() != "" { | |
| 251 pls.SetMeta("id", key.StringID()) | |
| 252 } else { | |
| 253 pls.SetMeta("id", key.IntID()) | |
| 254 } | |
| 255 pls.SetMeta("kind", key.Kind()) | |
| 256 pls.SetMeta("parent", key.Parent()) | |
| 257 } | |
| 258 } | |
| 259 | |
| 260 func mkPLSName(o interface{}) (PropertyLoadSaver, string) { | |
| 261 if pls, ok := o.(*structPLS); ok { | |
| 262 return pls, pls.o.Type().Name() | |
| 263 } | |
| 264 if pls, ok := o.(PropertyLoadSaver); ok { | |
| 265 return pls, "" | |
| 266 } | |
| 267 pls := GetPLS(o) | |
| 268 name := pls.(*structPLS).o.Type().Name() | |
| 269 return pls, name | |
| 270 } | |
| 271 | |
| 272 func getMetaString(pls PropertyLoadSaver, key, dflt string) string { | |
| 273 mstr, err := pls.GetMeta(key) | |
| 274 ret, ok := mstr.(string) | |
| 275 if err != nil || !ok { | |
| 276 return dflt | |
| 277 } | |
| 278 return ret | |
| 279 } | |
| 280 | |
| 281 func getMetaInt64(pls PropertyLoadSaver, key string, dflt int64) int64 { | |
| 282 mint, err := pls.GetMeta(key) | |
| 283 ret, ok := mint.(int64) | |
| 284 if err != nil || !ok { | |
| 285 return dflt | |
| 286 } | |
| 287 return ret | |
| 288 } | |
| 289 | |
| 290 func getMetaKey(pls PropertyLoadSaver, key string) Key { | |
| 291 mkey, _ := pls.GetMeta(key) | |
| 292 ret, _ := mkey.(Key) | |
| 293 return ret | |
| 294 } | |
| OLD | NEW |