github.com/bytedance/go-tagexpr/v2@v2.9.8/binding/func.go (about)

     1  package binding
     2  
     3  import (
     4  	jsonpkg "encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"reflect"
     8  	"time"
     9  
    10  	"github.com/andeya/ameda"
    11  	"google.golang.org/protobuf/proto"
    12  )
    13  
    14  // JSONUnmarshaler is the interface implemented by types
    15  // that can unmarshal a JSON description of themselves.
    16  type JSONUnmarshaler func(data []byte, v interface{}) error
    17  
    18  // ResetJSONUnmarshaler reset the JSON Unmarshal function.
    19  // NOTE: verifyingRequired is true if the required tag is supported.
    20  //
    21  // Deprecated: please use: Default().ResetJSONUnmarshaler
    22  func ResetJSONUnmarshaler(fn JSONUnmarshaler) {
    23  	defaultBinding.ResetJSONUnmarshaler(fn)
    24  }
    25  
    26  var typeUnmarshalFuncs = make(map[reflect.Type]func(string, bool) (reflect.Value, error))
    27  
    28  func unsafeUnmarshalValue(v reflect.Value, s string, looseZeroMode bool) error {
    29  	fn := typeUnmarshalFuncs[v.Type()]
    30  	if fn != nil {
    31  		vv, err := fn(s, looseZeroMode)
    32  		if err == nil {
    33  			v.Set(vv)
    34  		}
    35  		return err
    36  	}
    37  	return unmarshal(ameda.UnsafeStringToBytes(s), v.Addr().Interface())
    38  }
    39  
    40  func unsafeUnmarshalSlice(t reflect.Type, a []string, looseZeroMode bool) (reflect.Value, error) {
    41  	var err error
    42  	fn := typeUnmarshalFuncs[t]
    43  	if fn == nil {
    44  		fn = func(s string, _ bool) (reflect.Value, error) {
    45  			v := reflect.New(t)
    46  			i := v.Interface()
    47  			err = unmarshal(ameda.UnsafeStringToBytes(s), i)
    48  			return v.Elem(), err
    49  		}
    50  	}
    51  	v := reflect.New(reflect.SliceOf(t)).Elem()
    52  	for _, s := range a {
    53  		var vv reflect.Value
    54  		vv, err = fn(s, looseZeroMode)
    55  		if err != nil {
    56  			return v, err
    57  		}
    58  		v = reflect.Append(v, vv)
    59  	}
    60  	return v, nil
    61  }
    62  
    63  func unmarshal(b []byte, i interface{}) error {
    64  	switch x := i.(type) {
    65  	case jsonpkg.Unmarshaler:
    66  		return x.UnmarshalJSON(b)
    67  	case proto.Message:
    68  		return proto.Unmarshal(b, x)
    69  	default:
    70  		return jsonpkg.Unmarshal(b, i)
    71  	}
    72  }
    73  
    74  // MustRegTypeUnmarshal registers unmarshalor function of type.
    75  // NOTE:
    76  //
    77  //	panic if exist error.
    78  func MustRegTypeUnmarshal(t reflect.Type, fn func(v string, emptyAsZero bool) (reflect.Value, error)) {
    79  	err := RegTypeUnmarshal(t, fn)
    80  	if err != nil {
    81  		panic(err)
    82  	}
    83  }
    84  
    85  // RegTypeUnmarshal registers unmarshalor function of type.
    86  func RegTypeUnmarshal(t reflect.Type, fn func(v string, emptyAsZero bool) (reflect.Value, error)) error {
    87  	// check
    88  	switch t.Kind() {
    89  	case reflect.String, reflect.Bool,
    90  		reflect.Float32, reflect.Float64,
    91  		reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8,
    92  		reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
    93  		return errors.New("registration type cannot be a basic type")
    94  	case reflect.Ptr:
    95  		return errors.New("registration type cannot be a pointer type")
    96  	}
    97  	// test
    98  	vv, err := fn("", true)
    99  	if err != nil {
   100  		return fmt.Errorf("test fail: %s", err)
   101  	}
   102  	if tt := vv.Type(); tt != t {
   103  		return fmt.Errorf("test fail: expect return value type is %s, but got %s", t.String(), tt.String())
   104  	}
   105  
   106  	typeUnmarshalFuncs[t] = fn
   107  	return nil
   108  }
   109  
   110  func init() {
   111  	MustRegTypeUnmarshal(reflect.TypeOf(time.Time{}), func(v string, emptyAsZero bool) (reflect.Value, error) {
   112  		if v == "" && emptyAsZero {
   113  			return reflect.ValueOf(time.Time{}), nil
   114  		}
   115  		t, err := time.Parse(time.RFC3339, v)
   116  		if err != nil {
   117  			return reflect.Value{}, err
   118  		}
   119  		return reflect.ValueOf(t), nil
   120  	})
   121  }