github.com/searKing/golang/go@v1.2.117/encoding/defaults/type_convert.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package defaults 6 7 import "reflect" 8 9 // Convert v 10 // apply custom interface on v along with tag 11 func userDefinedConvertFunc(v reflect.Value, tag reflect.StructTag) (isUserDefined bool, err error) { 12 isUserDefined = true 13 if v.Kind() == reflect.Ptr && v.IsNil() { 14 return 15 } 16 m, ok := v.Interface().(Converter) 17 if !ok { 18 return 19 } 20 return isUserDefined, m.ConvertDefault(v, tag) 21 } 22 23 // Convert &v 24 // apply custom interface on &v along with tag 25 func addrUserDefinedConvertFunc(v reflect.Value, tag reflect.StructTag) (isUserDefined bool, err error) { 26 isUserDefined = true 27 vaddr := v.Addr() 28 if vaddr.IsNil() { 29 return 30 } 31 m := vaddr.Interface().(Converter) 32 return isUserDefined, m.ConvertDefault(v, tag) 33 } 34 35 // newTypeConverter constructs an convertFunc for a type. 36 // The returned encoder only checks CanAddr when allowAddr is true. 37 func newTypeConverter(convFn convertFunc, t reflect.Type, allowAddr bool) convertFunc { 38 // Handle UserDefined Case 39 // t.ConvertDefault(value, tag) 40 if t.Implements(converterType) { 41 return userDefinedConvertFunc 42 } 43 44 // Handle UserDefined Case 45 // Convert &v, iterate only once 46 // (&t).ConvertDefault(value, tag) || convFn(value, tag) 47 if t.Kind() != reflect.Ptr && allowAddr { 48 if reflect.PtrTo(t).Implements(converterType) { 49 return newCondAddrConvertFunc(addrUserDefinedConvertFunc, newTypeConverter(convFn, t, false)) 50 } 51 } 52 return convFn 53 } 54 55 // If CanAddr then get addr and handle else handle directly 56 type condAddrConvertFunc struct { 57 canAddrConvert, elseConvert convertFunc 58 } 59 60 func (ce *condAddrConvertFunc) handle(v reflect.Value, tag reflect.StructTag) (isUserDefined bool, err error) { 61 if v.CanAddr() { 62 return ce.canAddrConvert(v, tag) 63 } 64 return ce.elseConvert(v, tag) 65 } 66 67 // newCondAddrConverter returns an encoder that checks whether its structTag 68 // CanAddr and delegates to canAddrConvert if so, else to elseConvert. 69 func newCondAddrConvertFunc(canAddrConvert, elseConvert convertFunc) convertFunc { 70 convFn := &condAddrConvertFunc{canAddrConvert: canAddrConvert, elseConvert: elseConvert} 71 return convFn.handle 72 }