Skip to content

Encode and Decode custom type function, we can get match reflect.Type in callback! #65

@thinkgos

Description

@thinkgos

Package version eg. v4:

Issue, Question or Enhancement:

DecodeCustomTypeFunc should be not func([]string) (interface{}, error), may be func(reflect.Type,[]string) (interface{}, error) will be better.
also. EncodeCustomTypeFunc: func(x interface{}) ([]string, error) -> func(t reflect.Type, x interface{}) ([]string, error).

get the match reflect.Type. the custom type parse function can do more thing.

Code sample, to showcase or reproduce:

example below:

I want to parser id=1,2,3 to []int or []CustomInt or more.

type CustomInt int

func DecodeCustomIntSlice[T ~int](values []string) (any, error) {
	if len(values) == 0 {
		return []T{}, nil
	}
	// FIXME: make slice space
	ret := make([]T, 0)
	for _, s := range values {
		for _, v := range strings.Split(s, ",") {
			i, err := strconv.ParseInt(v, 10, 0)
			if err != nil {
				return nil, err
			}
			ret = append(ret, T(i))
		}
	}
	return ret, nil
}
dec := form.NewDecoder()
dec.SetTagName("json")
dec.RegisterCustomTypeFunc(DecodeCustomIntSlice[int], []int{})
dec.RegisterCustomTypeFunc(DecodeCustomIntSlice[CustomInt], []CustomInt{})

I have to register twice. if decoder.go#L191 pass the reflect.Type to custom type parser function, we can register in one line.

if DecodeCustomTypeFunc is func(reflect.Type,[]string) (interface{}, error), we can simple do below:

type CustomInt int
type CustomInt1 int
type CustomInt2 int

func DecodeCommaStringToSlice(t reflect.Type, values []string) (any, error) {
	if t.Kind() != reflect.Slice {
		return nil, &form.InvalidDecoderError{Type: t}
	}
	ret := reflect.MakeSlice(t, 0, 0)
	te := t.Elem()
	teKind := te.Kind()
	for _, s := range values {
		for _, ss := range strings.Split(s, ",") {
			switch teKind {
			case reflect.Int:
				i, err := strconv.ParseInt(ss, 10, 0)
				if err != nil {
					return nil, err
				}
				val := reflect.New(te).Elem()
				val.SetInt(i)
				ret = reflect.Append(ret, val)
			}
		}
	}
	return ret.Interface(), nil
}

dec := form.NewDecoder()
dec.SetTagName("json")
dec.RegisterCustomTypeFunc(DecodeCommaStringToSlice, []int{},[]CustomInt{},[]CustomInt1{},[]CustomInt2{})

Is there any other better solution?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions