Chromium Code Reviews| 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 |
|
dnj
2016/05/25 05:27:16
This has been moved to the bottom, and is now a fu
| |
| 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 func parseArg(et reflect.Type) *multiArgType { |
| 27 » if meta { | 27 » if et.Kind() == reflect.Interface { |
| 28 » » getter = func(slot reflect.Value) (PropertyMap, error) { | 28 » » return multiArgTypeInterface() |
| 29 » » » return mat.getMetaPM(slot), nil | 29 » } |
| 30 | |
| 31 » // If a map type implements an interface, its pointer is also considered to | |
|
dnj
2016/05/25 05:27:16
(This is why the map thing was so wonky. I didn't
| |
| 32 » // implement that interface. | |
| 33 » // | |
| 34 » // In this case, we have special pointer-to-map logic in multiArgTypePLS . | |
| 35 » if et.Implements(typeOfPropertyLoadSaver) { | |
| 36 » » return multiArgTypePLS(et) | |
| 37 » } | |
| 38 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) { | |
| 39 » » return multiArgTypePLSPtr(et) | |
| 40 » } | |
| 41 | |
| 42 » switch et.Kind() { | |
| 43 » case reflect.Ptr: | |
| 44 » » if et.Elem().Kind() == reflect.Struct { | |
| 45 » » » return multiArgTypeStructPtr(et) | |
| 30 } | 46 } |
| 47 | |
| 48 case reflect.Struct: | |
| 49 return multiArgTypeStruct(et) | |
| 31 } | 50 } |
| 32 » lme := errors.NewLazyMultiError(len(retKey)) | 51 |
| 33 » for i := range retKey { | 52 » 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 } | 53 } |
| 45 | 54 |
| 46 // parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some | 55 // 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 | 56 // struct type S, for some interface type I, or some non-interface non-pointer |
| 48 // type P such that P or *P implements PropertyLoadSaver. | 57 // type P such that P or *P implements PropertyLoadSaver. |
| 49 func parseMultiArg(e reflect.Type) multiArgType { | 58 func mustParseMultiArg(et reflect.Type) *multiArgType { |
| 50 » if e.Kind() != reflect.Slice { | 59 » if et.Kind() != reflect.Slice { |
| 51 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , e)) | 60 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , et)) |
| 52 } | 61 } |
| 53 » return parseArg(e.Elem(), true) | 62 » return mustParseArg(et.Elem()) |
| 54 } | 63 } |
| 55 | 64 |
| 56 // parseArg checks that et is of type S, *S, I, P or *P, for some | 65 func mustParseArg(et reflect.Type) *multiArgType { |
| 57 // struct type S, for some interface type I, or some non-interface non-pointer | 66 » if mat := parseArg(et); mat != nil { |
| 58 // type P such that P or *P implements PropertyLoadSaver. | 67 » » return mat |
| 59 func parseArg(et reflect.Type, multi bool) multiArgType { | |
| 60 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) { | |
| 61 » » return multiArgTypePLS(et) | |
| 62 } | 68 } |
| 63 » if et.Implements(typeOfPropertyLoadSaver) && et.Kind() != reflect.Interf ace { | 69 » 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 } | 70 } |
| 82 | 71 |
| 83 type newKeyFunc func(kind, sid string, iid int64, par Key) Key | 72 // multiArgTypePLS handles the case where et implements PropertyLoadSaver. |
| 84 | 73 // |
| 85 // multiArgTypePLS == []P | 74 // This handles the special case of pointer-to-map (see parseArg). |
| 86 // *P implements PropertyLoadSaver | 75 func multiArgTypePLS(et reflect.Type) *multiArgType { |
| 87 func multiArgTypePLS(et reflect.Type) multiArgType { | |
| 88 ret := multiArgType{ | 76 ret := multiArgType{ |
| 89 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | 77 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { |
| 90 » » » return newKeyObjErr(aid, ns, slot.Addr().Interface()) | 78 » » » 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 }, | 79 }, |
| 129 getPM: func(slot reflect.Value) (PropertyMap, error) { | 80 getPM: func(slot reflect.Value) (PropertyMap, error) { |
| 130 return slot.Interface().(PropertyLoadSaver).Save(true) | 81 return slot.Interface().(PropertyLoadSaver).Save(true) |
| 131 }, | 82 }, |
| 132 getMetaPM: func(slot reflect.Value) PropertyMap { | 83 getMetaPM: func(slot reflect.Value) PropertyMap { |
| 133 return getMGS(slot.Interface()).GetAllMeta() | 84 return getMGS(slot.Interface()).GetAllMeta() |
| 134 }, | 85 }, |
| 135 setPM: func(slot reflect.Value, pm PropertyMap) error { | 86 setPM: func(slot reflect.Value, pm PropertyMap) error { |
| 136 return slot.Interface().(PropertyLoadSaver).Load(pm) | 87 return slot.Interface().(PropertyLoadSaver).Load(pm) |
| 137 }, | 88 }, |
| 138 setKey: func(slot reflect.Value, k *Key) { | 89 setKey: func(slot reflect.Value, k *Key) { |
| 139 PopulateKey(slot.Interface(), k) | 90 PopulateKey(slot.Interface(), k) |
| 140 }, | 91 }, |
| 141 } | 92 } |
| 142 » if et.Kind() == reflect.Map { | 93 » switch et.Kind() { |
| 94 » case reflect.Map: | |
| 143 ret.newElem = func() reflect.Value { | 95 ret.newElem = func() reflect.Value { |
| 144 » » » ptr := reflect.New(et) | 96 » » » return reflect.MakeMap(et) |
| 145 » » » ptr.Elem().Set(reflect.MakeMap(et)) | |
| 146 » » » return ptr | |
| 147 } | 97 } |
| 148 » } else { | 98 |
| 149 » » ret.newElem = func() reflect.Value { return reflect.New(et) } | 99 » case reflect.Ptr: |
| 100 » » mapElem := et.Elem() | |
| 101 » » if mapElem.Kind() == reflect.Map { | |
| 102 » » » ret.newElem = func() reflect.Value { | |
| 103 » » » » ptr := reflect.New(mapElem) | |
| 104 » » » » ptr.Elem().Set(reflect.MakeMap(mapElem)) | |
| 105 » » » » return ptr | |
| 106 » » » } | |
| 107 » » } | |
| 150 } | 108 } |
| 151 » return ret | 109 |
| 110 » if ret.newElem == nil { | |
| 111 » » ret.newElem = func() reflect.Value { | |
| 112 » » » return reflect.New(et.Elem()) | |
| 113 » » } | |
| 114 » } | |
| 115 » return &ret | |
| 116 } | |
| 117 | |
| 118 // multiArgTypePLSPtr handles the case where et doesn't implement | |
| 119 // PropertyLoadSaver, but a pointer to et does. | |
| 120 func multiArgTypePLSPtr(et reflect.Type) *multiArgType { | |
| 121 » return &multiArgType{ | |
| 122 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | |
| 123 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e())) | |
| 124 » » }, | |
| 125 » » getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 126 » » » return slot.Addr().Interface().(PropertyLoadSaver).Save( true) | |
| 127 » » }, | |
| 128 » » getMetaPM: func(slot reflect.Value) PropertyMap { | |
| 129 » » » return getMGS(slot.Addr().Interface()).GetAllMeta() | |
| 130 » » }, | |
| 131 » » setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 132 » » » return slot.Addr().Interface().(PropertyLoadSaver).Load( pm) | |
| 133 » » }, | |
| 134 » » setKey: func(slot reflect.Value, k *Key) { | |
| 135 » » » PopulateKey(slot.Addr().Interface(), k) | |
| 136 » » }, | |
| 137 » » newElem: func() reflect.Value { | |
| 138 » » » return reflect.New(et).Elem() | |
| 139 » » }, | |
| 140 » } | |
| 152 } | 141 } |
| 153 | 142 |
| 154 // multiArgTypeStruct == []S | 143 // multiArgTypeStruct == []S |
| 155 func multiArgTypeStruct(et reflect.Type) multiArgType { | 144 func multiArgTypeStruct(et reflect.Type) *multiArgType { |
| 156 cdc := getCodec(et) | 145 cdc := getCodec(et) |
| 157 toPLS := func(slot reflect.Value) *structPLS { | 146 toPLS := func(slot reflect.Value) *structPLS { |
| 158 return &structPLS{slot, cdc} | 147 return &structPLS{slot, cdc} |
| 159 } | 148 } |
| 160 » return multiArgType{ | 149 » return &multiArgType{ |
| 161 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | 150 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { |
| 162 » » » return newKeyObjErr(aid, ns, toPLS(slot)) | 151 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e())) |
|
dnj
2016/05/25 05:27:16
This was a bug. MGS overrides wouldn't be honored.
| |
| 163 }, | 152 }, |
| 164 getPM: func(slot reflect.Value) (PropertyMap, error) { | 153 getPM: func(slot reflect.Value) (PropertyMap, error) { |
| 165 return toPLS(slot).Save(true) | 154 return toPLS(slot).Save(true) |
| 166 }, | 155 }, |
| 167 getMetaPM: func(slot reflect.Value) PropertyMap { | 156 getMetaPM: func(slot reflect.Value) PropertyMap { |
| 168 » » » if slot.Type().Implements(typeOfMGS) { | 157 » » » return getMGS(slot.Addr().Interface()).GetAllMeta() |
| 169 » » » » return slot.Interface().(MetaGetterSetter).GetAl lMeta() | |
| 170 » » » } | |
| 171 » » » return toPLS(slot).GetAllMeta() | |
| 172 }, | 158 }, |
| 173 setPM: func(slot reflect.Value, pm PropertyMap) error { | 159 setPM: func(slot reflect.Value, pm PropertyMap) error { |
| 174 return toPLS(slot).Load(pm) | 160 return toPLS(slot).Load(pm) |
| 175 }, | 161 }, |
| 176 setKey: func(slot reflect.Value, k *Key) { | 162 setKey: func(slot reflect.Value, k *Key) { |
| 177 PopulateKey(toPLS(slot), k) | 163 PopulateKey(toPLS(slot), k) |
| 178 }, | 164 }, |
| 179 newElem: func() reflect.Value { | 165 newElem: func() reflect.Value { |
| 180 return reflect.New(et).Elem() | 166 return reflect.New(et).Elem() |
| 181 }, | 167 }, |
| 182 } | 168 } |
| 183 } | 169 } |
| 184 | 170 |
| 185 // multiArgTypeStructPtr == []*S | 171 // multiArgTypeStructPtr == []*S |
| 186 func multiArgTypeStructPtr(et reflect.Type) multiArgType { | 172 func multiArgTypeStructPtr(et reflect.Type) *multiArgType { |
| 187 » cdc := getCodec(et) | 173 » cdc := getCodec(et.Elem()) |
| 188 toPLS := func(slot reflect.Value) *structPLS { | 174 toPLS := func(slot reflect.Value) *structPLS { |
| 189 return &structPLS{slot.Elem(), cdc} | 175 return &structPLS{slot.Elem(), cdc} |
| 190 } | 176 } |
| 191 » return multiArgType{ | 177 » return &multiArgType{ |
| 192 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | 178 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { |
| 193 » » » return newKeyObjErr(aid, ns, toPLS(slot)) | 179 » » » return newKeyObjErr(aid, ns, getMGS(slot.Interface())) |
| 194 }, | 180 }, |
| 195 getPM: func(slot reflect.Value) (PropertyMap, error) { | 181 getPM: func(slot reflect.Value) (PropertyMap, error) { |
| 196 return toPLS(slot).Save(true) | 182 return toPLS(slot).Save(true) |
| 197 }, | 183 }, |
| 198 getMetaPM: func(slot reflect.Value) PropertyMap { | 184 getMetaPM: func(slot reflect.Value) PropertyMap { |
| 199 » » » if slot.Elem().Type().Implements(typeOfMGS) { | 185 » » » return getMGS(slot.Interface()).GetAllMeta() |
| 200 » » » » return getMGS(slot.Interface()).GetAllMeta() | |
| 201 » » » } | |
| 202 » » » return toPLS(slot).GetAllMeta() | |
| 203 }, | 186 }, |
| 204 setPM: func(slot reflect.Value, pm PropertyMap) error { | 187 setPM: func(slot reflect.Value, pm PropertyMap) error { |
| 205 » » » return toPLS(slot).Load(pm) | 188 » » » err := toPLS(slot).Load(pm) |
|
dnj
2016/05/25 05:27:16
I'll collapse this in the next PS.
| |
| 189 » » » return err | |
| 206 }, | 190 }, |
| 207 setKey: func(slot reflect.Value, k *Key) { | 191 setKey: func(slot reflect.Value, k *Key) { |
| 208 PopulateKey(toPLS(slot), k) | 192 PopulateKey(toPLS(slot), k) |
| 209 }, | 193 }, |
| 210 newElem: func() reflect.Value { | 194 newElem: func() reflect.Value { |
| 211 » » » return reflect.New(et) | 195 » » » return reflect.New(et.Elem()) |
| 212 }, | 196 }, |
| 213 } | 197 } |
| 214 } | 198 } |
| 215 | 199 |
| 216 // multiArgTypeInterface == []I | 200 // multiArgTypeInterface == []I |
| 217 func multiArgTypeInterface() multiArgType { | 201 func multiArgTypeInterface() *multiArgType { |
| 218 » return multiArgType{ | 202 » return &multiArgType{ |
| 219 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | 203 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { |
| 220 » » » return newKeyObjErr(aid, ns, slot.Elem().Interface()) | 204 » » » return newKeyObjErr(aid, ns, getMGS(slot.Elem().Interfac e())) |
|
dnj
2016/05/25 05:27:16
This, I think, was a bug.
| |
| 221 }, | 205 }, |
| 222 getPM: func(slot reflect.Value) (PropertyMap, error) { | 206 getPM: func(slot reflect.Value) (PropertyMap, error) { |
| 223 return mkPLS(slot.Elem().Interface()).Save(true) | 207 return mkPLS(slot.Elem().Interface()).Save(true) |
| 224 }, | 208 }, |
| 225 getMetaPM: func(slot reflect.Value) PropertyMap { | 209 getMetaPM: func(slot reflect.Value) PropertyMap { |
| 226 return getMGS(slot.Elem().Interface()).GetAllMeta() | 210 return getMGS(slot.Elem().Interface()).GetAllMeta() |
| 227 }, | 211 }, |
| 228 setPM: func(slot reflect.Value, pm PropertyMap) error { | 212 setPM: func(slot reflect.Value, pm PropertyMap) error { |
| 229 return mkPLS(slot.Elem().Interface()).Load(pm) | 213 return mkPLS(slot.Elem().Interface()).Load(pm) |
| 230 }, | 214 }, |
| 231 setKey: func(slot reflect.Value, k *Key) { | 215 setKey: func(slot reflect.Value, k *Key) { |
| 232 PopulateKey(slot.Elem().Interface(), k) | 216 PopulateKey(slot.Elem().Interface(), k) |
| 233 }, | 217 }, |
| 234 } | 218 } |
| 235 } | 219 } |
| 236 | 220 |
| 237 func newKeyObjErr(aid, ns string, src interface{}) (*Key, error) { | 221 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) { |
| 238 » pls := getMGS(src) | 222 » if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil { |
| 239 » if key, _ := GetMetaDefault(pls, "key", nil).(*Key); key != nil { | |
| 240 return key, nil | 223 return key, nil |
| 241 } | 224 } |
| 242 | 225 |
| 243 // get kind | 226 // get kind |
| 244 » kind := GetMetaDefault(pls, "kind", "").(string) | 227 » kind := GetMetaDefault(mgs, "kind", "").(string) |
| 245 if kind == "" { | 228 if kind == "" { |
| 246 » » return nil, fmt.Errorf("unable to extract $kind from %T", src) | 229 » » return nil, errors.New("unable to extract $kind") |
| 247 } | 230 } |
| 248 | 231 |
| 249 // get id - allow both to be default for default keys | 232 // get id - allow both to be default for default keys |
| 250 » sid := GetMetaDefault(pls, "id", "").(string) | 233 » sid := GetMetaDefault(mgs, "id", "").(string) |
| 251 » iid := GetMetaDefault(pls, "id", 0).(int64) | 234 » iid := GetMetaDefault(mgs, "id", 0).(int64) |
| 252 | 235 |
| 253 // get parent | 236 // get parent |
| 254 » par, _ := GetMetaDefault(pls, "parent", nil).(*Key) | 237 » par, _ := GetMetaDefault(mgs, "parent", nil).(*Key) |
| 255 | 238 |
| 256 return NewKey(aid, ns, kind, sid, iid, par), nil | 239 return NewKey(aid, ns, kind, sid, iid, par), nil |
| 257 } | 240 } |
| 258 | 241 |
| 259 func mkPLS(o interface{}) PropertyLoadSaver { | 242 func mkPLS(o interface{}) PropertyLoadSaver { |
| 260 if pls, ok := o.(PropertyLoadSaver); ok { | 243 if pls, ok := o.(PropertyLoadSaver); ok { |
| 261 return pls | 244 return pls |
| 262 } | 245 } |
| 263 return GetPLS(o) | 246 return GetPLS(o) |
| 264 } | 247 } |
| 248 | |
| 249 func isOKSingleType(t reflect.Type) error { | |
| 250 if t == nil { | |
| 251 return errors.New("no type information") | |
| 252 } | |
| 253 if t.Implements(typeOfPropertyLoadSaver) { | |
| 254 return nil | |
| 255 } | |
| 256 if t == typeOfKey { | |
| 257 return errors.New("not user datatype") | |
| 258 } | |
| 259 if t.Kind() != reflect.Ptr { | |
| 260 return errors.New("not a pointer") | |
| 261 } | |
| 262 if t.Elem().Kind() != reflect.Struct { | |
| 263 return errors.New("does not point to a struct") | |
| 264 } | |
| 265 return nil | |
| 266 } | |
| 267 | |
| 268 type metaMultiArgElement struct { | |
| 269 arg reflect.Value | |
| 270 mat *multiArgType | |
| 271 size int // size is -1 if this element is not a slice. | |
| 272 } | |
| 273 | |
| 274 type metaMultiArg struct { | |
|
dnj
2016/05/25 05:27:16
*so meta*
But if there's a better name I might be
| |
| 275 elems []metaMultiArgElement | |
| 276 | |
| 277 count int // total number of elements, flattening slices | |
| 278 } | |
| 279 | |
| 280 func makeMetaMultiArg(args []interface{}) (*metaMultiArg, error) { | |
| 281 mma := metaMultiArg{ | |
| 282 elems: make([]metaMultiArgElement, len(args)), | |
| 283 } | |
| 284 | |
| 285 lme := errors.NewLazyMultiError(len(args)) | |
| 286 for i, arg := range args { | |
| 287 if arg == nil { | |
| 288 lme.Assign(i, errors.New("cannot use nil as single argum ent")) | |
| 289 continue | |
| 290 } | |
| 291 | |
| 292 v := reflect.ValueOf(arg) | |
| 293 vt := v.Type() | |
| 294 mma.elems[i].arg = v | |
| 295 | |
| 296 // Try and treat the argument as a single-value first. This allo ws slices | |
| 297 // that implement PropertyLoadSaver to be properly treated as a single | |
| 298 // element. | |
| 299 var err error | |
| 300 isSlice := false | |
| 301 mat := parseArg(vt) | |
| 302 if mat == nil { | |
| 303 // If this is a slice, treat it as a slice of arg candid ates. | |
| 304 if v.Kind() == reflect.Slice { | |
| 305 isSlice = true | |
| 306 mat = parseArg(vt.Elem()) | |
| 307 } | |
| 308 } else { | |
| 309 // Single types need to be able to be assigned to. | |
| 310 err = isOKSingleType(vt) | |
| 311 } | |
| 312 if mat == nil { | |
| 313 err = errors.New("not a PLS or pointer-to-struct") | |
| 314 } | |
| 315 if err != nil { | |
| 316 lme.Assign(i, fmt.Errorf("invalid input type (%T): %s", arg, err)) | |
| 317 continue | |
| 318 } | |
| 319 | |
| 320 mma.elems[i].mat = mat | |
| 321 if isSlice { | |
| 322 l := v.Len() | |
| 323 mma.count += l | |
| 324 mma.elems[i].size = l | |
| 325 } else { | |
| 326 mma.count++ | |
| 327 mma.elems[i].size = -1 | |
| 328 } | |
| 329 } | |
| 330 if err := lme.Get(); err != nil { | |
| 331 return nil, err | |
| 332 } | |
| 333 | |
| 334 return &mma, nil | |
| 335 } | |
| 336 | |
| 337 func (mma *metaMultiArg) iterator() *metaMultiArgIterator { | |
| 338 return &metaMultiArgIterator{ | |
| 339 metaMultiArg: mma, | |
| 340 | |
| 341 elemErrors: errors.NewLazyMultiError(len(mma.elems)), | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 // getKeysPMs returns the | |
| 346 func (mma *metaMultiArg) getKeysPMs(aid, ns string, meta bool) ([]*Key, []Proper tyMap, error) { | |
| 347 it := mma.iterator() | |
| 348 | |
| 349 // Determine our flattened keys and property maps. | |
| 350 retKey := make([]*Key, mma.count) | |
| 351 retPM := make([]PropertyMap, mma.count) | |
| 352 | |
| 353 for i := 0; i < mma.count; i++ { | |
| 354 it.next(func(mat *multiArgType, slot reflect.Value) error { | |
| 355 key, err := mat.getKey(aid, ns, slot) | |
| 356 if err != nil { | |
| 357 return err | |
| 358 } | |
| 359 retKey[i] = key | |
| 360 | |
| 361 var pm PropertyMap | |
| 362 if meta { | |
| 363 pm = mat.getMetaPM(slot) | |
| 364 } else { | |
| 365 var err error | |
| 366 if pm, err = mat.getPM(slot); err != nil { | |
| 367 return err | |
| 368 } | |
| 369 } | |
| 370 retPM[i] = pm | |
| 371 return nil | |
| 372 }) | |
| 373 } | |
| 374 return retKey, retPM, it.error() | |
| 375 } | |
| 376 | |
| 377 type metaMultiArgIterator struct { | |
| 378 *metaMultiArg | |
| 379 | |
| 380 elemErrors errors.LazyMultiError | |
| 381 sliceErrors map[int]errors.LazyMultiError | |
| 382 | |
| 383 index int // flattened index | |
| 384 elemIdx int // current index in slice | |
| 385 slotIdx int // current index within elemIdx element (0 if single) | |
| 386 } | |
| 387 | |
| 388 func (mac *metaMultiArgIterator) next(fn func(*multiArgType, reflect.Value) erro r) { | |
| 389 if mac.remaining() <= 0 { | |
| 390 panic("out of bounds") | |
| 391 } | |
| 392 | |
| 393 // Get the current element and slot. | |
| 394 elem := &mac.elems[mac.elemIdx] | |
| 395 | |
| 396 // Get the current slot value. | |
| 397 slot := elem.arg | |
| 398 if elem.size >= 0 { | |
| 399 // slot is a slice type, get its member. | |
| 400 slot = slot.Index(mac.slotIdx) | |
| 401 } | |
| 402 | |
| 403 // Execute our callback. | |
| 404 if err := fn(elem.mat, slot); err != nil { | |
| 405 // If this is a single element, assign the error directly. | |
| 406 if elem.size < 0 { | |
| 407 mac.elemErrors.Assign(mac.elemIdx, err) | |
| 408 } else { | |
| 409 // This is a slice element. Use a slice-sized MultiError for its element | |
| 410 // error slot, then add this error to the inner MultiErr or's slot index. | |
| 411 ilme := mac.sliceErrors[mac.elemIdx] | |
| 412 if ilme == nil { | |
| 413 ilme = errors.NewLazyMultiError(elem.size) | |
| 414 | |
| 415 if mac.sliceErrors == nil { | |
| 416 mac.sliceErrors = make(map[int]errors.La zyMultiError) | |
| 417 } | |
| 418 mac.sliceErrors[mac.elemIdx] = ilme | |
| 419 } | |
| 420 ilme.Assign(mac.slotIdx, err) | |
| 421 } | |
| 422 } | |
| 423 | |
| 424 // Advance to the next element/slot. | |
| 425 mac.index++ | |
| 426 mac.slotIdx++ | |
| 427 if mac.slotIdx >= elem.size { | |
| 428 mac.elemIdx++ | |
| 429 mac.slotIdx = 0 | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 func (mac *metaMultiArgIterator) error() error { | |
| 434 lme := errors.NewLazyMultiError(len(mac.elems)) | |
| 435 for i, elem := range mac.elems { | |
| 436 if elem.size < 0 { | |
| 437 lme.Assign(i, mac.elemErrors.GetOne(i)) | |
| 438 } else { | |
| 439 if serr := mac.sliceErrors[i]; serr != nil { | |
| 440 lme.Assign(i, serr.Get()) | |
| 441 } | |
| 442 } | |
| 443 } | |
| 444 return lme.Get() | |
| 445 } | |
| 446 | |
| 447 func (mac *metaMultiArgIterator) remaining() int { | |
| 448 return mac.count - mac.index | |
| 449 } | |
| OLD | NEW |