binder

package module
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2023 License: Apache-2.0 Imports: 17 Imported by: 6

README

Go Binder Build Status GoDoc License

Provide a common binder to bind a value to any, for example, binding a struct to a map.

For the struct, the package registers github.com/xgfone/go-structs.Reflect to reflect the fields of struct to validate the struct value. And, github.com/xgfone/go-validation.Validate may be used to validate each field value of the struct based on the built rule.

Install

$ go get -u github.com/xgfone/go-binder

Example

Bind the basic types
package main

import (
	"fmt"
	"reflect"
	"time"

	"github.com/xgfone/go-binder"
)

func main() {
	type (
		IntT    int
		UintT   uint
		FloatT  float64
		StringT string
	)

	var (
		Bool    bool
		Int     int
		Int8    int8
		Int16   int16
		Int32   int32
		Int64   int64
		Uint    uint
		Uint8   uint8
		Uint16  uint16
		Uint32  uint32
		Uint64  uint64
		Float32 float32
		Float64 float64
		String  string

		intT    IntT
		uintT   UintT
		floatT  FloatT
		stringT StringT
	)

	println := func(dst, src interface{}) {
		err := binder.Bind(dst, src)
		fmt.Println(reflect.ValueOf(dst).Elem().Interface(), err)
	}

	println(&Bool, "true")
	println(&Int, time.Second)
	println(&Int8, 11.0)
	println(&Int16, "12")
	println(&Int32, true)
	println(&Int64, time.Unix(1672531200, 0))
	println(&Uint, 20)
	println(&Uint8, 21.0)
	println(&Uint16, "22")
	println(&Uint32, true)
	println(&Uint64, 23)
	println(&Float32, "1.2")
	println(&Float64, 30)
	println(&String, 40)

	println(&intT, 50.0)
	println(&uintT, IntT(60))
	println(&floatT, StringT("70"))
	println(&stringT, "test")

	// Output:
	// true <nil>
	// 1000 <nil>
	// 11 <nil>
	// 12 <nil>
	// 1 <nil>
	// 1672531200 <nil>
	// 20 <nil>
	// 21 <nil>
	// 22 <nil>
	// 1 <nil>
	// 23 <nil>
	// 1.2 <nil>
	// 30 <nil>
	// 40 <nil>
	// 50 <nil>
	// 60 <nil>
	// 70 <nil>
	// test <nil>
}
Bind the struct
package main

import (
	"fmt"
	"time"

	"github.com/xgfone/go-binder"
)

func main() {
	type (
		Int    int
		Uint   uint
		String string
		Float  float64
	)

	var S struct {
		Bool    bool
		Int     int
		Int8    int8
		Int16   int16
		Int32   int32
		Int64   int64
		Uint    uint
		Uint8   uint8
		Uint16  uint16
		Uint32  uint32
		Uint64  uint64
		Float32 float32
		Float64 float64
		String  string

		Duration1 time.Duration
		Duration2 time.Duration
		Duration3 time.Duration
		Time1     time.Time
		Time2     time.Time

		Embed struct {
			Int1 int
			Int2 Int

			Uint1 uint
			Uint2 Uint

			String1 string
			String2 String

			Float1 float64
			Float2 Float
		}

		Ignore string `json:"-"`
		Squash struct {
			Field1 int
			Field2 int
		} `json:",squash"`
	}

	maps := map[string]interface{}{
		"Bool": true,

		"Int":   10,
		"Int8":  11,
		"Int16": 12,
		"Int32": 13,
		"Int64": 14,

		"Uint":   20,
		"Uint8":  21,
		"Uint16": 22,
		"Uint32": 23,
		"Uint64": 24,

		"Float32": 30,
		"Float64": 31,

		"String":    "abc",
		"Duration1": "1s",                   // string => time.Duration
		"Duration2": 2000,                   // int(ms) => time.Duration
		"Duration3": 3.0,                    // float(s) => time.Duration
		"Time1":     1672531200,             // int(unix timestamp) => time.Time
		"Time2":     "2023-02-01T00:00:00Z", // string(RFC3339) => time.Time

		"Embed": map[string]interface{}{
			"Int1":    "41", // string => int
			"Int2":    "42", // string => Int
			"Uint1":   "43", // string => uint
			"Uint2":   "44", // string => Uint
			"Float1":  "45", // string => float64
			"Float2":  "46", // string => Float
			"String1": 47,   // int => string
			"String2": 48,   // int => String
		},

		"Ignore": "xyz",
		"Field1": 51,
		"Field2": 52,
	}

	err := binder.Bind(&S, maps)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("Bool=%v\n", S.Bool)
	fmt.Printf("Int=%v\n", S.Int)
	fmt.Printf("Int8=%v\n", S.Int8)
	fmt.Printf("Int16=%v\n", S.Int16)
	fmt.Printf("Int32=%v\n", S.Int32)
	fmt.Printf("Int64=%v\n", S.Int64)
	fmt.Printf("Uint=%v\n", S.Uint)
	fmt.Printf("Uint8=%v\n", S.Uint8)
	fmt.Printf("Uint16=%v\n", S.Uint16)
	fmt.Printf("Uint32=%v\n", S.Uint32)
	fmt.Printf("Uint64=%v\n", S.Uint64)
	fmt.Printf("Float32=%v\n", S.Float32)
	fmt.Printf("Float64=%v\n", S.Float64)
	fmt.Printf("String=%v\n", S.String)
	fmt.Printf("Duration1=%v\n", S.Duration1)
	fmt.Printf("Duration2=%v\n", S.Duration2)
	fmt.Printf("Duration3=%v\n", S.Duration3)
	fmt.Printf("Time1=%v\n", S.Time1.Format(time.RFC3339))
	fmt.Printf("Time2=%v\n", S.Time2.Format(time.RFC3339))
	fmt.Printf("Embed.Int1=%v\n", S.Embed.Int1)
	fmt.Printf("Embed.Int2=%v\n", S.Embed.Int2)
	fmt.Printf("Embed.Uint1=%v\n", S.Embed.Uint1)
	fmt.Printf("Embed.Uint2=%v\n", S.Embed.Uint2)
	fmt.Printf("Embed.String1=%v\n", S.Embed.String1)
	fmt.Printf("Embed.String2=%v\n", S.Embed.String2)
	fmt.Printf("Embed.Float1=%v\n", S.Embed.Float1)
	fmt.Printf("Embed.Float2=%v\n", S.Embed.Float2)
	fmt.Printf("Squash.Field1=%v\n", S.Squash.Field1)
	fmt.Printf("Squash.Field2=%v\n", S.Squash.Field2)
	fmt.Printf("Ignore=%v\n", S.Ignore)

	// Output:
	// Bool=true
	// Int=10
	// Int8=11
	// Int16=12
	// Int32=13
	// Int64=14
	// Uint=20
	// Uint8=21
	// Uint16=22
	// Uint32=23
	// Uint64=24
	// Float32=30
	// Float64=31
	// String=abc
	// Duration1=1s
	// Duration2=2s
	// Duration3=3s
	// Time1=2023-01-01T00:00:00Z
	// Time2=2023-02-01T00:00:00Z
	// Embed.Int1=41
	// Embed.Int2=42
	// Embed.Uint1=43
	// Embed.Uint2=44
	// Embed.String1=47
	// Embed.String2=48
	// Embed.Float1=45
	// Embed.Float2=46
	// Squash.Field1=51
	// Squash.Field2=52
	// Ignore=
}
Bind the containers
package main

import (
	"fmt"
	"net/url"

	"github.com/xgfone/go-binder"
)

func main() {
	type Ints []int
	var S struct {
		Maps    map[string]interface{} `json:"maps"`
		Slices  []string               `json:"slices"`
		Structs []struct {
			Ints  Ints       `json:"ints"`
			Query url.Values `json:"query"`
		} `json:"structs"`
	}

	maps := map[string]interface{}{
		"maps":   map[string]string{"k11": "v11", "k12": "v12"},
		"slices": []interface{}{"a", "b", "c"},
		"structs": []map[string]interface{}{
			{
				"ints": []string{"21", "22"},
				"query": map[string][]string{
					"k20": {"v21", "v22"},
					"k30": {"v31", "v32"},
				},
			},
			{
				"ints": []int{31, 32},
				"query": map[string][]string{
					"k40": {"v40"},
				},
			},
		},
	}

	err := binder.Bind(&S, maps)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("Maps: %v\n", S.Maps)
	fmt.Printf("Slices: %v\n", S.Slices)
	for i, s := range S.Structs {
		fmt.Printf("Structs[%d]: Ints=%v, Query=%v\n", i, s.Ints, s.Query)
	}

	// Output:
	// Maps: map[k11:v11 k12:v12]
	// Slices: [a b c]
	// Structs[0]: Ints=[21 22], Query=map[k20:[v21 v22] k30:[v31 v32]]
	// Structs[1]: Ints=[31 32], Query=map[k40:[v40]]
}
Bind the interfaces
package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/xgfone/go-binder"
)

// Int is the customized int.
type Int int

// Set implements the interface binder.Setter.
func (i *Int) Set(src interface{}) (err error) {
	switch v := src.(type) {
	case int:
		*i = Int(v)
	case string:
		var _v int64
		_v, err = strconv.ParseInt(v, 10, 64)
		if err == nil {
			*i = Int(_v)
		}
	default:
		err = fmt.Errorf("unsupport to convert %T to Int", src)
	}
	return
}

func (i Int) String() string {
	return fmt.Sprint(int64(i))
}

// Struct is the customized struct.
type Struct struct {
	Name string
	Age  Int
}

// UnmarshalBind implements the interface binder.Unmarshaler.
func (s *Struct) UnmarshalBind(src interface{}) (err error) {
	if maps, ok := src.(map[string]interface{}); ok {
		s.Name, _ = maps["Name"].(string)
		err = s.Age.Set(maps["Age"])
		return
	}
	return fmt.Errorf("unsupport to convert %T to a struct", src)
}

func (s Struct) String() string {
	return fmt.Sprintf("Name=%s, Age=%d", s.Name, s.Age)
}

func main() {
	var iface1 Int
	var iface2 Struct
	var S = struct {
		Interface1 binder.Setter
		Interface2 binder.Unmarshaler

		Interface3 error
		Interface4 *error

		Interface5 interface{} // Use to store any type value.
		// binder.Unmarshaler  // Do not use the anonymous interface.
	}{
		Interface1: &iface1, // For interface, must be set to a pointer
		Interface2: &iface2, //  to an implementation.
	}

	iface3 := errors.New("test1")
	iface4 := errors.New("test2")
	maps := map[string]interface{}{
		"Interface1": "123",
		"Interface2": map[string]interface{}{"Name": "Aaron", "Age": 18},
		"Interface3": iface3,
		"Interface4": iface4,
		"Interface5": "any",
	}

	err := binder.Bind(&S, maps)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("Interface1: %v\n", S.Interface1)
	fmt.Printf("Interface2: %v\n", S.Interface2)
	fmt.Printf("Interface3: %v\n", S.Interface3)
	fmt.Printf("Interface4: %v\n", *S.Interface4)
	fmt.Printf("Interface5: %v\n", S.Interface5)

	// Output:
	// Interface1: 123
	// Interface2: Name=Aaron, Age=18
	// Interface3: test1
	// Interface4: test2
	// Interface5: any
}
Hook
package main

import (
	"fmt"
	"mime/multipart"
	"reflect"

	"github.com/xgfone/go-binder"
)

func main() {
	src := map[string][]*multipart.FileHeader{
		"file":  {{Filename: "file"}},
		"files": {{Filename: "file1"}, {Filename: "file2"}},
	}

	var dst struct {
		File  *multipart.FileHeader   `json:"file"`
		Files []*multipart.FileHeader `json:"files"`
	}

	// (xgf) By default, the binder cannot bind *multipart.FileHeader
	// to []*multipart.FileHeader. However, we can use hook to do it.
	// Here, there are two ways to finish it:
	//   1. We just convert []*multipart.FileHeader to *multipart.FileHeader,
	//      then let the binder continue to finish binding.
	//   2. We finish the binding in the hook.
	//   3. Set ConvertSliceToSingle to true to enable the auto-conversion.
	// In the exmaple, we use the first.
	multiparthook := func(dst reflect.Value, src interface{}) (interface{}, error) {
		if _, ok := dst.Interface().(*multipart.FileHeader); !ok {
			return src, nil // Let the binder continue to handle it.
		}

		srcfiles, ok := src.([]*multipart.FileHeader)
		if !ok {
			return src, nil // Let the binder continue to handle it.
		} else if len(srcfiles) == 0 {
			return nil, nil // FileHeader is empty, we tell the binder not to do it.
		}
		return srcfiles[0], nil
	}

	err := binder.Binder{Hook: multiparthook}.Bind(&dst, src)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("File.Filename=%s\n", dst.File.Filename)
	for i, file := range dst.Files {
		fmt.Printf("Files[%d].Filename=%s\n", i, file.Filename)
	}

	// Output:
	// File.Filename=file
	// Files[0].Filename=file1
	// Files[1].Filename=file2
}
Bind HTTP Request Body
func main() {
	http.HandleFunc("/path", func(w http.ResponseWriter, r *http.Request) {
		var body struct {
			Field int `json:"field"`
			// ...
		}
		err := binder.BodyDecoder.Decode(&body, r)
		// ...
	})
}
Bind HTTP Request Query
func main() {
	http.HandleFunc("/path", func(w http.ResponseWriter, r *http.Request) {
		var query struct {
			Field int `query:"field"`
			// ...
		}
		err := binder.QueryDecoder.Decode(&query, r)
		// ...
	})
}
Bind HTTP Request Header
func main() {
	http.HandleFunc("/path", func(w http.ResponseWriter, r *http.Request) {
		var header struct {
			Field int `header:"x-field"` // or "X-Field"
			// ...
		}
		err := binder.HeaderDecoder.Decode(&header, r)
		// ...
	})
}

Documentation

Overview

Package binder provides a common binder to bind a value to any, for example, binding a struct to a map.

Index

Examples

Constants

This section is empty.

Variables

View Source
var DefaultBinder = NewBinder()

DefaultBinder is the default binder.

Functions

func Bind

func Bind(dstptr, src interface{}) error

Bind uses DefaultBinder to bind dstptr to src.

func BindStructToHTTPHeader

func BindStructToHTTPHeader(structptr interface{}, tag string, data http.Header) error

BindStructToHTTPHeader binds the struct to http.Header.

For the key name, it will use textproto.CanonicalMIMEHeaderKey(s) to normalize it.

Example
src := http.Header{
	"X-Int":  []string{"1", "2"},
	"X-Ints": []string{"3", "4"},
	"X-Str":  []string{"a", "b"},
	"X-Strs": []string{"c", "d"},
}

var dst struct {
	unexported string   `header:"-"`
	Other      string   `header:"Other"`
	Int        int      `header:"x-int"`
	Ints       []int    `header:"x-ints"`
	Str        string   `header:"x-str"`
	Strs       []string `header:"x-strs"`
}

err := BindStructToHTTPHeader(&dst, "header", src)
if err != nil {
	fmt.Println(err)
} else {
	fmt.Printf("unexported=%s\n", dst.unexported)
	fmt.Printf("Other=%s\n", dst.Other)
	fmt.Printf("Int=%d\n", dst.Int)
	fmt.Printf("Ints=%d\n", dst.Ints)
	fmt.Printf("Str=%s\n", dst.Str)
	fmt.Printf("Strs=%s\n", dst.Strs)
}
Output:

unexported=
Other=
Int=1
Ints=[3 4]
Str=a
Strs=[c d]

func BindStructToMap

func BindStructToMap(structptr interface{}, tag string, data map[string]interface{}) (err error)

BindStructToMap binds the struct to map[string]interface{}.

For the key name, it is case-sensitive.

func BindStructToMultipartFileHeaders

func BindStructToMultipartFileHeaders(structptr interface{}, tag string, fhs map[string][]*multipart.FileHeader) error

BindStructToMultipartFileHeaders binds the struct to the multipart form file headers.

For the key name, it is case-sensitive.

Example
src := map[string][]*multipart.FileHeader{
	"file":  {{Filename: "file"}},
	"files": {{Filename: "file1"}, {Filename: "file2"}},
	"_file": {{Filename: "file3"}},
}

var dst struct {
	Other       string                  `form:"Other"`
	_File       *multipart.FileHeader   `form:"_file"` // unexported, so ignored
	FileHeader  *multipart.FileHeader   `form:"file"`
	FileHeaders []*multipart.FileHeader `form:"files"`
}

err := BindStructToMultipartFileHeaders(&dst, "form", src)
if err != nil {
	fmt.Println(err)
} else {
	fmt.Println(dst.FileHeader.Filename)
	if dst._File != nil {
		fmt.Println(dst._File.Filename)
	}
	for _, fh := range dst.FileHeaders {
		fmt.Println(fh.Filename)
	}
}
Output:

file
file1
file2

func BindStructToStringMap

func BindStructToStringMap(structptr interface{}, tag string, data map[string]string) (err error)

BindStructToStringMap binds the struct to map[string]string.

For the key name, it is case-sensitive.

Example
src := map[string]string{
	"Int": "123",
	"Str": "456",
}

var dst struct {
	Int  int `tag:"-"`
	Int1 int `tag:"Int"`
	Int2 int `tag:"Str"`
}

err := BindStructToStringMap(&dst, "tag", src)
if err != nil {
	fmt.Println(err)
} else {
	fmt.Printf("Int=%d\n", dst.Int)
	fmt.Printf("Int1=%d\n", dst.Int1)
	fmt.Printf("Int2=%d\n", dst.Int2)
}
Output:

Int=0
Int1=123
Int2=456

func BindStructToURLValues

func BindStructToURLValues(structptr interface{}, tag string, data url.Values) error

BindStructToURLValues binds the struct to url.Values.

For the key name, it is case-sensitive.

Example
src := url.Values{
	"int":  []string{"1", "2"},
	"ints": []string{"3", "4"},
	"str":  []string{"a", "b"},
	"strs": []string{"c", "d"},
}

var dst struct {
	unexported string   `qeury:"-"`
	Other      string   `query:"Other"`
	Int        int      `query:"int"`
	Ints       []int    `query:"ints"`
	Str        string   `query:"str"`
	Strs       []string `query:"strs"`
}

err := BindStructToURLValues(&dst, "query", src)
if err != nil {
	fmt.Println(err)
} else {
	fmt.Printf("unexported=%s\n", dst.unexported)
	fmt.Printf("Other=%s\n", dst.Other)
	fmt.Printf("Int=%d\n", dst.Int)
	fmt.Printf("Ints=%d\n", dst.Ints)
	fmt.Printf("Str=%s\n", dst.Str)
	fmt.Printf("Strs=%s\n", dst.Strs)
}
Output:

unexported=
Other=
Int=1
Ints=[3 4]
Str=a
Strs=[c d]

func BindWithTag

func BindWithTag(dstptr, src interface{}, tag string) error

BindWithTag is used to bind dstptr to src, which uses the given tag to try to get the field name.

Types

type Binder

type Binder struct {
	// If true, convert src from slice/array, that's the first element,
	// to a single value on demand by the bound value.
	ConvertSliceToSingle bool

	// if true, convert src from a single value to slice/array on demand
	// by the bound value.
	ConvertSingleToSlice bool

	// GetFieldName is used to get the name and arg of the given field.
	//
	// If nil, use defaults.GetStructFieldName instead.
	//
	// If ignoring the field, return the empty string for the field name.
	// For the tag value, it maybe contain the argument, just like
	//   type S struct {
	//       OnlyName    int `json:"fieldname"`
	//       OnlyArg     int `json:",fieldarg"`
	//       NameAndArg  int `json:"fieldname,fieldarg"`
	//       NameAndArgs int `json:"fieldname,fieldarg1,fieldarg2"`
	//       Ignore1     int `json:"-"`
	//       Ignore2     int `json:"-,"`
	//   }
	//
	// For the field argument, it only supports "squash" to squash
	// all the fields of the struct, just like the anonymous field.
	GetFieldName func(reflect.StructField) (name, arg string)

	// Hook is used to intercept the binding operation if set.
	//
	// If newsrc is not nil, the engine will continue to handle it.
	// Or, ignore it and go on to bind the next value.
	// So, if the hook has bound the value, return (nil, nil).
	//
	// Default: nil
	Hook Hook
}

Binder is a common binder to bind a value to any.

In general, Binder is used to transform a value between different types.

func NewBinder

func NewBinder() Binder

NewBinder returns a default binder.

func NewBinderWithHook

func NewBinderWithHook(hook Hook) Binder

NewBinderWithHook returns a default binder with the hook.

func (Binder) Bind

func (b Binder) Bind(dstptr, src interface{}) error

Bind is used to bind the value dstptr to src.

In general, dstptr is a pointer to a contain variable. Moreover, dstptr may be a reflect.Value, but it must can be set or a pointer that the element can be set.

Support the types of the struct fields as follow:

  • ~bool
  • ~int
  • ~int8
  • ~int16
  • ~int32
  • ~int64
  • ~uint
  • ~uint8
  • ~uint16
  • ~uint32
  • ~uint64
  • ~string
  • ~float32
  • ~float64
  • ~Array[E]
  • ~Slice[E]
  • ~Map[E]V
  • time.Time
  • time.Duration
  • Struct

And any pointer to the types above, and the interfaces Unmarshaler and Setter.

type Decoder added in v0.2.0

type Decoder interface {
	Decode(dst, src interface{}) error
}

Decoder is used to decode the data src to dst.

In general, Deocder is used to decode a byte stream to a type, such as struct or map.

var (
	// It only supports to decode *http.Request with the tag "query" by default.
	DefaultQueryDecoder Decoder = DecoderFunc(func(dst, src interface{}) error {
		if req, ok := src.(*http.Request); ok {
			return BindStructToURLValues(dst, "query", req.URL.Query())
		}
		return fmt.Errorf("binder.DefaultQueryDecoder: unsupport to decode %T", src)
	})

	// It only supports to decode *http.Request with the tag "header" by default.
	DefaultHeaderDecoder Decoder = DecoderFunc(func(dst, src interface{}) error {
		if req, ok := src.(*http.Request); ok {
			return BindStructToHTTPHeader(dst, "header", req.Header)
		}
		return fmt.Errorf("binder.DefaultHeaderDecoder: unsupport to decode %T", src)
	})

	// By default, during initializing the package, it will register
	// some decoders for the http request with the content-types:
	//   - "application/xml"
	//   - "application/json"
	//   - "multipart/form-data"
	//   - "application/x-www-form-urlencoded"
	// For the http request, it can be used like
	//   DefaultMuxDecoder.Decode(dst, httpRequest).
	DefaultMuxDecoder = NewMuxDecoder()

	// It will use defaults.ValidateStruct to validate the struct value by default.
	DefaultStructValidationDecoder Decoder = StructValidationDecoder(nil)

	// Some encapsulated http decoders, which can be used directly.
	BodyDecoder   Decoder = ComposeDecoders(DefaultMuxDecoder, DefaultStructValidationDecoder)
	QueryDecoder  Decoder = ComposeDecoders(DefaultQueryDecoder, DefaultStructValidationDecoder)
	HeaderDecoder Decoder = ComposeDecoders(DefaultHeaderDecoder, DefaultStructValidationDecoder)
)

Predefine some decoders to decode a value, such as body, query and header of the http request.

func ComposeDecoders added in v0.2.0

func ComposeDecoders(decoders ...Decoder) Decoder

ComposeDecoders composes a group of decoders, which will be called in turn, to a Decoder.

func StructValidationDecoder added in v0.2.0

func StructValidationDecoder(validator assists.StructValidator) Decoder

StructValidationDecoder returns a struct validation decoder, which only validates whether the value dst is valid, not decodes any.

type DecoderFunc added in v0.2.0

type DecoderFunc func(dst, src interface{}) error

DecoderFunc is a function to decode the data src to dst.

func (DecoderFunc) Decode added in v0.2.0

func (f DecoderFunc) Decode(dst, src interface{}) error

Decode implements the interface Decoder.

type Hook

type Hook func(dst reflect.Value, src interface{}) (newsrc interface{}, err error)

Hook is used to intercept the binding operation.

type MuxDecoder added in v0.2.0

type MuxDecoder struct {
	// GetDecoder is used to get the deocder by the funciton get
	// with decoder that comes from src.
	//
	// If nil, use the default implementation, which inspects the decoder type
	// by the type of src, and supports the types as follow:
	//   *http.Request: => Content-Type
	//   interface{ DecodeType() string }
	//   interface{ Type() string }
	GetDecoder func(src interface{}, get func(string) Decoder) (Decoder, error)
	// contains filtered or unexported fields
}

MuxDecoder is a multiplexer for kinds of Decoders.

func NewMuxDecoder added in v0.2.0

func NewMuxDecoder() *MuxDecoder

NewMuxDecoder returns a new MuxDecoder.

func (*MuxDecoder) Add added in v0.2.0

func (md *MuxDecoder) Add(dtype string, decoder Decoder)

Add adds a decoder to decode the data of the given type.

func (*MuxDecoder) Decode added in v0.2.0

func (md *MuxDecoder) Decode(dst, src interface{}) (err error)

Decode implements the interface Decoder.

func (*MuxDecoder) Del added in v0.2.0

func (md *MuxDecoder) Del(dtype string)

Del removes the corresponding decoder by the type.

func (*MuxDecoder) Get added in v0.2.0

func (md *MuxDecoder) Get(dtype string) Decoder

Get returns the corresponding decoder by the type.

Return nil if not found.

type Setter

type Setter interface {
	Set(interface{}) error
}

Setter is an interface to set itself to the parameter.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalBind(interface{}) error
}

Unmarshaler is an interface to unmarshal itself from the parameter.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL