| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be 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 » getMGS func(slot reflect.Value) MetaGetterSetter |
| 16 » getPM func(slot reflect.Value) (PropertyMap, error) | 16 » getPLS func(slot reflect.Value) PropertyLoadSaver |
| 17 » getMetaPM func(slot reflect.Value) PropertyMap | 17 » newElem func() reflect.Value |
| 18 » setPM func(slot reflect.Value, pm PropertyMap) error | 18 } |
| 19 » setKey func(slot reflect.Value, k *Key) | 19 |
| 20 » newElem func() reflect.Value | 20 func (mat *multiArgType) getKey(aid, ns string, slot reflect.Value) (*Key, error
) { |
| 21 » return newKeyObjErr(aid, ns, mat.getMGS(slot)) |
| 22 } |
| 23 |
| 24 func (mat *multiArgType) getPM(slot reflect.Value) (PropertyMap, error) { |
| 25 » return mat.getPLS(slot).Save(true) |
| 26 } |
| 27 |
| 28 func (mat *multiArgType) getMetaPM(slot reflect.Value) PropertyMap { |
| 29 » return mat.getMGS(slot).GetAllMeta() |
| 30 } |
| 31 |
| 32 func (mat *multiArgType) setPM(slot reflect.Value, pm PropertyMap) error { |
| 33 » return mat.getPLS(slot).Load(pm) |
| 34 } |
| 35 |
| 36 func (mat *multiArgType) setKey(slot reflect.Value, k *Key) { |
| 37 » PopulateKey(mat.getMGS(slot), k) |
| 21 } | 38 } |
| 22 | 39 |
| 23 // parseArg checks that et is of type S, *S, I, P or *P, for some | 40 // parseArg checks that et is of type S, *S, I, P or *P, for some |
| 24 // struct type S, for some interface type I, or some non-interface non-pointer | 41 // struct type S, for some interface type I, or some non-interface non-pointer |
| 25 // type P such that P or *P implements PropertyLoadSaver. | 42 // type P such that P or *P implements PropertyLoadSaver. |
| 26 // | 43 // |
| 27 // If et is a chan type that implements PropertyLoadSaver, new elements will be | 44 // If et is a chan type that implements PropertyLoadSaver, new elements will be |
| 28 // allocated with a buffer of 0. | 45 // allocated with a buffer of 0. |
| 29 // | 46 // |
| 30 // If keysOnly is true, a read-only key extraction multiArgType will be | 47 // If keysOnly is true, a read-only key extraction multiArgType will be |
| 31 // returned if et is a *Key. | 48 // returned if et is a *Key. |
| 32 func parseArg(et reflect.Type, keysOnly bool) *multiArgType { | 49 func parseArg(et reflect.Type, keysOnly bool) *multiArgType { |
| 50 var mat multiArgType |
| 51 |
| 33 if keysOnly && et == typeOfKey { | 52 if keysOnly && et == typeOfKey { |
| 34 » » return multiArgTypeKeyExtraction() | 53 » » mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return
&keyExtractionMGS{key: slot.Interface().(*Key)} } |
| 54 » » return &mat |
| 35 } | 55 } |
| 36 | 56 |
| 37 » if et.Kind() == reflect.Interface { | 57 » // If we do identify a structCodec for this type, retain it so we don't |
| 38 » » return multiArgTypeInterface() | 58 » // resolve it multiple times. |
| 59 » var codec *structCodec |
| 60 » initCodec := func(t reflect.Type) *structCodec { |
| 61 » » if codec == nil { |
| 62 » » » codec = getCodec(t) |
| 63 » » } |
| 64 » » return codec |
| 39 } | 65 } |
| 40 | 66 |
| 67 // Fill in MetaGetterSetter functions. |
| 68 switch { |
| 69 case et.Implements(typeOfMetaGetterSetter): |
| 70 // MGS |
| 71 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return
slot.Interface().(MetaGetterSetter) } |
| 72 |
| 73 case reflect.PtrTo(et).Implements(typeOfMetaGetterSetter): |
| 74 // *MGS |
| 75 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return
slot.Addr().Interface().(MetaGetterSetter) } |
| 76 |
| 77 default: |
| 78 switch et.Kind() { |
| 79 case reflect.Interface: |
| 80 // I |
| 81 mat.getMGS = func(slot reflect.Value) MetaGetterSetter {
return getMGS(slot.Elem().Interface()) } |
| 82 |
| 83 case reflect.Ptr: |
| 84 // *S |
| 85 if et.Elem().Kind() != reflect.Struct { |
| 86 // Not a struct pointer. |
| 87 return nil |
| 88 } |
| 89 |
| 90 initCodec(et.Elem()) |
| 91 mat.getMGS = func(slot reflect.Value) MetaGetterSetter {
return &structPLS{slot.Elem(), codec, nil} } |
| 92 |
| 93 case reflect.Struct: |
| 94 // S |
| 95 initCodec(et) |
| 96 mat.getMGS = func(slot reflect.Value) MetaGetterSetter {
return &structPLS{slot, codec, nil} } |
| 97 |
| 98 default: |
| 99 // Don't know how to get MGS for this type. |
| 100 return nil |
| 101 } |
| 102 } |
| 103 |
| 104 // Fill in PropertyLoadSaver functions. |
| 105 switch { |
| 106 case et.Implements(typeOfPropertyLoadSaver): |
| 107 // PLS |
| 108 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return
slot.Interface().(PropertyLoadSaver) } |
| 109 |
| 110 case reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver): |
| 111 // *PLS |
| 112 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return
slot.Addr().Interface().(PropertyLoadSaver) } |
| 113 |
| 114 default: |
| 115 switch et.Kind() { |
| 116 case reflect.Interface: |
| 117 // I |
| 118 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver
{ |
| 119 obj := slot.Elem().Interface() |
| 120 if pls, ok := obj.(PropertyLoadSaver); ok { |
| 121 return pls |
| 122 } |
| 123 return GetPLS(obj) |
| 124 } |
| 125 |
| 126 case reflect.Ptr: |
| 127 // *S |
| 128 if et.Elem().Kind() != reflect.Struct { |
| 129 // Not a struct pointer. |
| 130 return nil |
| 131 } |
| 132 initCodec(et.Elem()) |
| 133 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver
{ return &structPLS{slot.Elem(), codec, nil} } |
| 134 |
| 135 case reflect.Struct: |
| 136 // S |
| 137 initCodec(et) |
| 138 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver
{ return &structPLS{slot, codec, nil} } |
| 139 |
| 140 default: |
| 141 // Don't know how to get PLS for this type. |
| 142 return nil |
| 143 } |
| 144 } |
| 145 |
| 146 // Generate new element. |
| 147 // |
| 41 // If a map/chan type implements an interface, its pointer is also consi
dered | 148 // If a map/chan type implements an interface, its pointer is also consi
dered |
| 42 // to implement that interface. | 149 // to implement that interface. |
| 43 // | 150 // |
| 44 // In this case, we have special pointer-to-map/chan logic in multiArgTy
pePLS. | 151 // In this case, we have special pointer-to-map/chan logic in multiArgTy
pePLS. |
| 45 » if et.Implements(typeOfPropertyLoadSaver) { | 152 » mat.newElem = func() reflect.Value { |
| 46 » » return multiArgTypePLS(et) | 153 » » return reflect.New(et).Elem() |
| 47 » } | |
| 48 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) { | |
| 49 » » return multiArgTypePLSPtr(et) | |
| 50 } | 154 } |
| 51 | 155 |
| 52 switch et.Kind() { | 156 switch et.Kind() { |
| 53 case reflect.Ptr: | |
| 54 if et.Elem().Kind() == reflect.Struct { | |
| 55 return multiArgTypeStructPtr(et) | |
| 56 } | |
| 57 | |
| 58 case reflect.Struct: | |
| 59 return multiArgTypeStruct(et) | |
| 60 } | |
| 61 | |
| 62 return nil | |
| 63 } | |
| 64 | |
| 65 // parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some | |
| 66 // struct type S, for some interface type I, or some non-interface non-pointer | |
| 67 // type P such that P or *P implements PropertyLoadSaver. | |
| 68 func mustParseMultiArg(et reflect.Type) *multiArgType { | |
| 69 if et.Kind() != reflect.Slice { | |
| 70 panic(fmt.Errorf("invalid argument type: expected slice, got %s"
, et)) | |
| 71 } | |
| 72 return mustParseArg(et.Elem()) | |
| 73 } | |
| 74 | |
| 75 func mustParseArg(et reflect.Type) *multiArgType { | |
| 76 if mat := parseArg(et, false); mat != nil { | |
| 77 return mat | |
| 78 } | |
| 79 panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-s
truct", et)) | |
| 80 } | |
| 81 | |
| 82 // multiArgTypePLS handles the case where et implements PropertyLoadSaver. | |
| 83 // | |
| 84 // This handles the special case of pointer-to-map and pointer-to-chan ( | |
| 85 // see parseArg). | |
| 86 func multiArgTypePLS(et reflect.Type) *multiArgType { | |
| 87 ret := multiArgType{ | |
| 88 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | |
| 89 return newKeyObjErr(aid, ns, getMGS(slot.Interface())) | |
| 90 }, | |
| 91 getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 92 return slot.Interface().(PropertyLoadSaver).Save(true) | |
| 93 }, | |
| 94 getMetaPM: func(slot reflect.Value) PropertyMap { | |
| 95 return getMGS(slot.Interface()).GetAllMeta() | |
| 96 }, | |
| 97 setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 98 return slot.Interface().(PropertyLoadSaver).Load(pm) | |
| 99 }, | |
| 100 setKey: func(slot reflect.Value, k *Key) { | |
| 101 PopulateKey(slot.Interface(), k) | |
| 102 }, | |
| 103 } | |
| 104 switch et.Kind() { | |
| 105 case reflect.Map: | 157 case reflect.Map: |
| 106 » » ret.newElem = func() reflect.Value { | 158 » » mat.newElem = func() reflect.Value { |
| 107 return reflect.MakeMap(et) | 159 return reflect.MakeMap(et) |
| 108 } | 160 } |
| 109 | 161 |
| 110 case reflect.Chan: | 162 case reflect.Chan: |
| 111 » » ret.newElem = func() reflect.Value { | 163 » » mat.newElem = func() reflect.Value { |
| 112 return reflect.MakeChan(et, 0) | 164 return reflect.MakeChan(et, 0) |
| 113 } | 165 } |
| 114 | 166 |
| 115 case reflect.Ptr: | 167 case reflect.Ptr: |
| 116 elem := et.Elem() | 168 elem := et.Elem() |
| 117 switch elem.Kind() { | 169 switch elem.Kind() { |
| 118 case reflect.Map: | 170 case reflect.Map: |
| 119 » » » ret.newElem = func() reflect.Value { | 171 » » » mat.newElem = func() reflect.Value { |
| 120 ptr := reflect.New(elem) | 172 ptr := reflect.New(elem) |
| 121 ptr.Elem().Set(reflect.MakeMap(elem)) | 173 ptr.Elem().Set(reflect.MakeMap(elem)) |
| 122 return ptr | 174 return ptr |
| 123 } | 175 } |
| 124 | 176 |
| 125 case reflect.Chan: | 177 case reflect.Chan: |
| 126 » » » ret.newElem = func() reflect.Value { | 178 » » » mat.newElem = func() reflect.Value { |
| 127 ptr := reflect.New(elem) | 179 ptr := reflect.New(elem) |
| 128 ptr.Elem().Set(reflect.MakeChan(elem, 0)) | 180 ptr.Elem().Set(reflect.MakeChan(elem, 0)) |
| 129 return ptr | 181 return ptr |
| 130 } | 182 } |
| 183 |
| 184 default: |
| 185 mat.newElem = func() reflect.Value { return reflect.New(
et.Elem()) } |
| 131 } | 186 } |
| 187 |
| 188 case reflect.Interface: |
| 189 mat.newElem = nil |
| 132 } | 190 } |
| 133 | 191 |
| 134 » if ret.newElem == nil { | 192 » return &mat |
| 135 » » ret.newElem = func() reflect.Value { | |
| 136 » » » return reflect.New(et.Elem()) | |
| 137 » » } | |
| 138 » } | |
| 139 » return &ret | |
| 140 } | 193 } |
| 141 | 194 |
| 142 // multiArgTypePLSPtr handles the case where et doesn't implement | 195 // mustParseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for |
| 143 // PropertyLoadSaver, but a pointer to et does. | 196 // some struct type S, for some interface type I, or some non-interface |
| 144 func multiArgTypePLSPtr(et reflect.Type) *multiArgType { | 197 // non-pointer type P such that P or *P implements PropertyLoadSaver. |
| 145 » return &multiArgType{ | 198 func mustParseMultiArg(et reflect.Type) *multiArgType { |
| 146 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | 199 » if et.Kind() != reflect.Slice { |
| 147 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac
e())) | 200 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s"
, et)) |
| 148 » » }, | |
| 149 » » getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 150 » » » return slot.Addr().Interface().(PropertyLoadSaver).Save(
true) | |
| 151 » » }, | |
| 152 » » getMetaPM: func(slot reflect.Value) PropertyMap { | |
| 153 » » » return getMGS(slot.Addr().Interface()).GetAllMeta() | |
| 154 » » }, | |
| 155 » » setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 156 » » » return slot.Addr().Interface().(PropertyLoadSaver).Load(
pm) | |
| 157 » » }, | |
| 158 » » setKey: func(slot reflect.Value, k *Key) { | |
| 159 » » » PopulateKey(slot.Addr().Interface(), k) | |
| 160 » » }, | |
| 161 » » newElem: func() reflect.Value { | |
| 162 » » » return reflect.New(et).Elem() | |
| 163 » » }, | |
| 164 } | 201 } |
| 202 return mustParseArg(et.Elem()) |
| 165 } | 203 } |
| 166 | 204 |
| 167 // multiArgTypeStruct == []S | 205 func mustParseArg(et reflect.Type) *multiArgType { |
| 168 func multiArgTypeStruct(et reflect.Type) *multiArgType { | 206 » if mat := parseArg(et, false); mat != nil { |
| 169 » cdc := getCodec(et) | 207 » » return mat |
| 170 » toPLS := func(slot reflect.Value) *structPLS { | |
| 171 » » return &structPLS{slot, cdc} | |
| 172 } | 208 } |
| 173 » return &multiArgType{ | 209 » panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-s
truct", et)) |
| 174 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | |
| 175 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac
e())) | |
| 176 » » }, | |
| 177 » » getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 178 » » » return toPLS(slot).Save(true) | |
| 179 » » }, | |
| 180 » » getMetaPM: func(slot reflect.Value) PropertyMap { | |
| 181 » » » return getMGS(slot.Addr().Interface()).GetAllMeta() | |
| 182 » » }, | |
| 183 » » setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 184 » » » return toPLS(slot).Load(pm) | |
| 185 » » }, | |
| 186 » » setKey: func(slot reflect.Value, k *Key) { | |
| 187 » » » PopulateKey(toPLS(slot), k) | |
| 188 » » }, | |
| 189 » » newElem: func() reflect.Value { | |
| 190 » » » return reflect.New(et).Elem() | |
| 191 » » }, | |
| 192 » } | |
| 193 } | |
| 194 | |
| 195 // multiArgTypeStructPtr == []*S | |
| 196 func multiArgTypeStructPtr(et reflect.Type) *multiArgType { | |
| 197 » cdc := getCodec(et.Elem()) | |
| 198 » toPLS := func(slot reflect.Value) *structPLS { | |
| 199 » » return &structPLS{slot.Elem(), cdc} | |
| 200 » } | |
| 201 » return &multiArgType{ | |
| 202 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | |
| 203 » » » return newKeyObjErr(aid, ns, getMGS(slot.Interface())) | |
| 204 » » }, | |
| 205 » » getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 206 » » » return toPLS(slot).Save(true) | |
| 207 » » }, | |
| 208 » » getMetaPM: func(slot reflect.Value) PropertyMap { | |
| 209 » » » return getMGS(slot.Interface()).GetAllMeta() | |
| 210 » » }, | |
| 211 » » setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 212 » » » return toPLS(slot).Load(pm) | |
| 213 » » }, | |
| 214 » » setKey: func(slot reflect.Value, k *Key) { | |
| 215 » » » PopulateKey(toPLS(slot), k) | |
| 216 » » }, | |
| 217 » » newElem: func() reflect.Value { | |
| 218 » » » return reflect.New(et.Elem()) | |
| 219 » » }, | |
| 220 » } | |
| 221 } | |
| 222 | |
| 223 // multiArgTypeInterface == []I | |
| 224 func multiArgTypeInterface() *multiArgType { | |
| 225 » return &multiArgType{ | |
| 226 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | |
| 227 » » » return newKeyObjErr(aid, ns, getMGS(slot.Elem().Interfac
e())) | |
| 228 » » }, | |
| 229 » » getPM: func(slot reflect.Value) (PropertyMap, error) { | |
| 230 » » » return mkPLS(slot.Elem().Interface()).Save(true) | |
| 231 » » }, | |
| 232 » » getMetaPM: func(slot reflect.Value) PropertyMap { | |
| 233 » » » return getMGS(slot.Elem().Interface()).GetAllMeta() | |
| 234 » » }, | |
| 235 » » setPM: func(slot reflect.Value, pm PropertyMap) error { | |
| 236 » » » return mkPLS(slot.Elem().Interface()).Load(pm) | |
| 237 » » }, | |
| 238 » » setKey: func(slot reflect.Value, k *Key) { | |
| 239 » » » PopulateKey(slot.Elem().Interface(), k) | |
| 240 » » }, | |
| 241 » } | |
| 242 } | |
| 243 | |
| 244 // multiArgTypeKeyExtraction == *Key | |
| 245 // | |
| 246 // This ONLY implements getKey. | |
| 247 func multiArgTypeKeyExtraction() *multiArgType { | |
| 248 » return &multiArgType{ | |
| 249 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { | |
| 250 » » » return slot.Interface().(*Key), nil | |
| 251 » » }, | |
| 252 » } | |
| 253 } | 210 } |
| 254 | 211 |
| 255 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) { | 212 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) { |
| 256 if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil { | 213 if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil { |
| 257 return key, nil | 214 return key, nil |
| 258 } | 215 } |
| 259 | 216 |
| 260 // get kind | 217 // get kind |
| 261 kind := GetMetaDefault(mgs, "kind", "").(string) | 218 kind := GetMetaDefault(mgs, "kind", "").(string) |
| 262 if kind == "" { | 219 if kind == "" { |
| 263 return nil, errors.New("unable to extract $kind") | 220 return nil, errors.New("unable to extract $kind") |
| 264 } | 221 } |
| 265 | 222 |
| 266 // get id - allow both to be default for default keys | 223 // get id - allow both to be default for default keys |
| 267 sid := GetMetaDefault(mgs, "id", "").(string) | 224 sid := GetMetaDefault(mgs, "id", "").(string) |
| 268 iid := GetMetaDefault(mgs, "id", 0).(int64) | 225 iid := GetMetaDefault(mgs, "id", 0).(int64) |
| 269 | 226 |
| 270 // get parent | 227 // get parent |
| 271 par, _ := GetMetaDefault(mgs, "parent", nil).(*Key) | 228 par, _ := GetMetaDefault(mgs, "parent", nil).(*Key) |
| 272 | 229 |
| 273 return NewKey(aid, ns, kind, sid, iid, par), nil | 230 return NewKey(aid, ns, kind, sid, iid, par), nil |
| 274 } | 231 } |
| 275 | 232 |
| 276 func mkPLS(o interface{}) PropertyLoadSaver { | |
| 277 if pls, ok := o.(PropertyLoadSaver); ok { | |
| 278 return pls | |
| 279 } | |
| 280 return GetPLS(o) | |
| 281 } | |
| 282 | |
| 283 func isOKSingleType(t reflect.Type, keysOnly bool) error { | 233 func isOKSingleType(t reflect.Type, keysOnly bool) error { |
| 284 switch { | 234 switch { |
| 285 case t == nil: | 235 case t == nil: |
| 286 return errors.New("no type information") | 236 return errors.New("no type information") |
| 287 case t.Implements(typeOfPropertyLoadSaver): | 237 case t.Implements(typeOfPropertyLoadSaver): |
| 288 return nil | 238 return nil |
| 289 case !keysOnly && t == typeOfKey: | 239 case !keysOnly && t == typeOfKey: |
| 290 return errors.New("not user datatype") | 240 return errors.New("not user datatype") |
| 241 |
| 291 case t.Kind() != reflect.Ptr: | 242 case t.Kind() != reflect.Ptr: |
| 292 return errors.New("not a pointer") | 243 return errors.New("not a pointer") |
| 293 case t.Elem().Kind() != reflect.Struct: | 244 case t.Elem().Kind() != reflect.Struct: |
| 294 return errors.New("does not point to a struct") | 245 return errors.New("does not point to a struct") |
| 246 |
| 295 default: | 247 default: |
| 296 return nil | 248 return nil |
| 297 } | 249 } |
| 298 } | 250 } |
| 299 | 251 |
| 252 // keyExtractionMGS is a MetaGetterSetter that wraps a key and only implements |
| 253 // GetMeta, and even then only retrieves the wrapped key meta value, "key". |
| 254 type keyExtractionMGS struct { |
| 255 MetaGetterSetter |
| 256 |
| 257 key *Key |
| 258 } |
| 259 |
| 260 func (mgs *keyExtractionMGS) GetMeta(key string) (interface{}, bool) { |
| 261 if key == "key" { |
| 262 return mgs.key, true |
| 263 } |
| 264 return nil, false |
| 265 } |
| 266 |
| 300 type metaMultiArgElement struct { | 267 type metaMultiArgElement struct { |
| 301 arg reflect.Value | 268 arg reflect.Value |
| 302 mat *multiArgType | 269 mat *multiArgType |
| 303 size int // size is -1 if this element is not a slice. | 270 size int // size is -1 if this element is not a slice. |
| 304 } | 271 } |
| 305 | 272 |
| 306 type metaMultiArg struct { | 273 type metaMultiArg struct { |
| 307 elems []metaMultiArgElement | 274 elems []metaMultiArgElement |
| 308 keysOnly bool | 275 keysOnly bool |
| 309 | 276 |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 default: | 506 default: |
| 540 // Pass through to track as MultiError. | 507 // Pass through to track as MultiError. |
| 541 bt.errorTracker.trackError(it, err) | 508 bt.errorTracker.trackError(it, err) |
| 542 } | 509 } |
| 543 } | 510 } |
| 544 | 511 |
| 545 func (bt *boolTracker) result() *ExistsResult { | 512 func (bt *boolTracker) result() *ExistsResult { |
| 546 bt.res.updateSlices() | 513 bt.res.updateSlices() |
| 547 return &bt.res | 514 return &bt.res |
| 548 } | 515 } |
| OLD | NEW |