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  }