| | |
| | |
| | |
| |
|
| | |
| |
|
| | package json |
| |
|
| | import ( |
| | "errors" |
| | "fmt" |
| | "io" |
| | "reflect" |
| | "sync" |
| |
|
| | "encoding/json/internal" |
| | "encoding/json/internal/jsonflags" |
| | "encoding/json/internal/jsonopts" |
| | "encoding/json/jsontext" |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | var SkipFunc = errors.New("json: skip function") |
| |
|
| | var errSkipMutation = errors.New("must not read or write any tokens when skipping") |
| | var errNonSingularValue = errors.New("must read or write exactly one value") |
| |
|
| | |
| | |
| | |
| | |
| | |
| | type Marshalers = typedMarshalers |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func JoinMarshalers(ms ...*Marshalers) *Marshalers { |
| | return newMarshalers(ms...) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | type Unmarshalers = typedUnmarshalers |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func JoinUnmarshalers(us ...*Unmarshalers) *Unmarshalers { |
| | return newUnmarshalers(us...) |
| | } |
| |
|
| | type typedMarshalers = typedArshalers[jsontext.Encoder] |
| | type typedUnmarshalers = typedArshalers[jsontext.Decoder] |
| | type typedArshalers[Coder any] struct { |
| | nonComparable |
| |
|
| | fncVals []typedArshaler[Coder] |
| | fncCache sync.Map |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | fromAny bool |
| | } |
| | type typedMarshaler = typedArshaler[jsontext.Encoder] |
| | type typedUnmarshaler = typedArshaler[jsontext.Decoder] |
| | type typedArshaler[Coder any] struct { |
| | typ reflect.Type |
| | fnc func(*Coder, addressableValue, *jsonopts.Struct) error |
| | maySkip bool |
| | } |
| |
|
| | func newMarshalers(ms ...*Marshalers) *Marshalers { return newTypedArshalers(ms...) } |
| | func newUnmarshalers(us ...*Unmarshalers) *Unmarshalers { return newTypedArshalers(us...) } |
| | func newTypedArshalers[Coder any](as ...*typedArshalers[Coder]) *typedArshalers[Coder] { |
| | var a typedArshalers[Coder] |
| | for _, a2 := range as { |
| | if a2 != nil { |
| | a.fncVals = append(a.fncVals, a2.fncVals...) |
| | a.fromAny = a.fromAny || a2.fromAny |
| | } |
| | } |
| | if len(a.fncVals) == 0 { |
| | return nil |
| | } |
| | return &a |
| | } |
| |
|
| | func (a *typedArshalers[Coder]) lookup(fnc func(*Coder, addressableValue, *jsonopts.Struct) error, t reflect.Type) (func(*Coder, addressableValue, *jsonopts.Struct) error, bool) { |
| | if a == nil { |
| | return fnc, false |
| | } |
| | if v, ok := a.fncCache.Load(t); ok { |
| | if v == nil { |
| | return fnc, false |
| | } |
| | return v.(func(*Coder, addressableValue, *jsonopts.Struct) error), true |
| | } |
| |
|
| | |
| | |
| | var fncs []func(*Coder, addressableValue, *jsonopts.Struct) error |
| | for _, fncVal := range a.fncVals { |
| | if !castableTo(t, fncVal.typ) { |
| | continue |
| | } |
| | fncs = append(fncs, fncVal.fnc) |
| | if !fncVal.maySkip { |
| | break |
| | } |
| | } |
| |
|
| | if len(fncs) == 0 { |
| | a.fncCache.Store(t, nil) |
| | return fnc, false |
| | } |
| |
|
| | |
| | fncDefault := fnc |
| | fnc = func(c *Coder, v addressableValue, o *jsonopts.Struct) error { |
| | for _, fnc := range fncs { |
| | if err := fnc(c, v, o); err != SkipFunc { |
| | return err |
| | } |
| | } |
| | return fncDefault(c, v, o) |
| | } |
| |
|
| | |
| | v, _ := a.fncCache.LoadOrStore(t, fnc) |
| | return v.(func(*Coder, addressableValue, *jsonopts.Struct) error), true |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers { |
| | t := reflect.TypeFor[T]() |
| | assertCastableTo(t, true) |
| | typFnc := typedMarshaler{ |
| | typ: t, |
| | fnc: func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { |
| | v, _ := reflect.TypeAssert[T](va.castTo(t)) |
| | val, err := fn(v) |
| | if err != nil { |
| | err = wrapSkipFunc(err, "marshal function of type func(T) ([]byte, error)") |
| | if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalFunc") |
| | } |
| | err = newMarshalErrorBefore(enc, t, err) |
| | return collapseSemanticErrors(err) |
| | } |
| | if err := enc.WriteValue(val); err != nil { |
| | if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalFunc") |
| | } |
| | if isSyntacticError(err) { |
| | err = newMarshalErrorBefore(enc, t, err) |
| | } |
| | return err |
| | } |
| | return nil |
| | }, |
| | } |
| | return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers { |
| | t := reflect.TypeFor[T]() |
| | assertCastableTo(t, true) |
| | typFnc := typedMarshaler{ |
| | typ: t, |
| | fnc: func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { |
| | xe := export.Encoder(enc) |
| | prevDepth, prevLength := xe.Tokens.DepthLength() |
| | xe.Flags.Set(jsonflags.WithinArshalCall | 1) |
| | v, _ := reflect.TypeAssert[T](va.castTo(t)) |
| | err := fn(enc, v) |
| | xe.Flags.Set(jsonflags.WithinArshalCall | 0) |
| | currDepth, currLength := xe.Tokens.DepthLength() |
| | if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) { |
| | err = errNonSingularValue |
| | } |
| | if err != nil { |
| | if err == SkipFunc { |
| | if prevDepth == currDepth && prevLength == currLength { |
| | return SkipFunc |
| | } |
| | err = errSkipMutation |
| | } |
| | if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalToFunc") |
| | } |
| | if !export.IsIOError(err) { |
| | err = newSemanticErrorWithPosition(enc, t, prevDepth, prevLength, err) |
| | } |
| | return err |
| | } |
| | return nil |
| | }, |
| | maySkip: true, |
| | } |
| | return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers { |
| | t := reflect.TypeFor[T]() |
| | assertCastableTo(t, false) |
| | typFnc := typedUnmarshaler{ |
| | typ: t, |
| | fnc: func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { |
| | val, err := dec.ReadValue() |
| | if err != nil { |
| | return err |
| | } |
| | v, _ := reflect.TypeAssert[T](va.castTo(t)) |
| | err = fn(val, v) |
| | if err != nil { |
| | err = wrapSkipFunc(err, "unmarshal function of type func([]byte, T) error") |
| | if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | return err |
| | } |
| | err = newUnmarshalErrorAfter(dec, t, err) |
| | return collapseSemanticErrors(err) |
| | } |
| | return nil |
| | }, |
| | } |
| | return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers { |
| | t := reflect.TypeFor[T]() |
| | assertCastableTo(t, false) |
| | typFnc := typedUnmarshaler{ |
| | typ: t, |
| | fnc: func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { |
| | xd := export.Decoder(dec) |
| | prevDepth, prevLength := xd.Tokens.DepthLength() |
| | if prevDepth == 1 && xd.AtEOF() { |
| | return io.EOF |
| | } |
| | xd.Flags.Set(jsonflags.WithinArshalCall | 1) |
| | v, _ := reflect.TypeAssert[T](va.castTo(t)) |
| | err := fn(dec, v) |
| | xd.Flags.Set(jsonflags.WithinArshalCall | 0) |
| | currDepth, currLength := xd.Tokens.DepthLength() |
| | if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) { |
| | err = errNonSingularValue |
| | } |
| | if err != nil { |
| | if err == SkipFunc { |
| | if prevDepth == currDepth && prevLength == currLength { |
| | return SkipFunc |
| | } |
| | err = errSkipMutation |
| | } |
| | if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { |
| | if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil { |
| | return err2 |
| | } |
| | return err |
| | } |
| | if !isSyntacticError(err) && !export.IsIOError(err) { |
| | err = newSemanticErrorWithPosition(dec, t, prevDepth, prevLength, err) |
| | } |
| | return err |
| | } |
| | return nil |
| | }, |
| | maySkip: true, |
| | } |
| | return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func assertCastableTo(to reflect.Type, marshal bool) { |
| | switch to.Kind() { |
| | case reflect.Interface: |
| | return |
| | case reflect.Pointer: |
| | |
| | |
| | if to.Name() == "" { |
| | return |
| | } |
| | default: |
| | |
| | |
| | |
| | if marshal { |
| | return |
| | } |
| | } |
| | if marshal { |
| | panic(fmt.Sprintf("input type %v must be an interface type, an unnamed pointer type, or a non-pointer type", to)) |
| | } else { |
| | panic(fmt.Sprintf("input type %v must be an interface type or an unnamed pointer type", to)) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func castableTo(from, to reflect.Type) bool { |
| | switch to.Kind() { |
| | case reflect.Interface: |
| | |
| | |
| | |
| | |
| | return reflect.PointerTo(from).Implements(to) |
| | case reflect.Pointer: |
| | |
| | |
| | return reflect.PointerTo(from) == to |
| | default: |
| | |
| | |
| | return from == to |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (va addressableValue) castTo(to reflect.Type) reflect.Value { |
| | switch to.Kind() { |
| | case reflect.Interface: |
| | return va.Addr().Convert(to) |
| | case reflect.Pointer: |
| | return va.Addr() |
| | default: |
| | return va.Value |
| | } |
| | } |
| |
|
| | |
| | |
| | func castableToFromAny(to reflect.Type) bool { |
| | for _, from := range []reflect.Type{anyType, boolType, stringType, float64Type, mapStringAnyType, sliceAnyType} { |
| | if castableTo(from, to) { |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| |
|
| | func wrapSkipFunc(err error, what string) error { |
| | if err == SkipFunc { |
| | return errors.New(what + " cannot be skipped") |
| | } |
| | return err |
| | } |
| |
|