chord/vendor/github.com/go-json-experiment/json/arshal_methods.go
2025-03-15 20:42:37 -04:00

336 lines
12 KiB
Go

// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"encoding"
"errors"
"reflect"
"github.com/go-json-experiment/json/internal"
"github.com/go-json-experiment/json/internal/jsonflags"
"github.com/go-json-experiment/json/internal/jsonopts"
"github.com/go-json-experiment/json/internal/jsonwire"
"github.com/go-json-experiment/json/jsontext"
)
var errNonStringValue = errors.New("JSON value must be string type")
// Interfaces for custom serialization.
var (
jsonMarshalerType = reflect.TypeFor[Marshaler]()
jsonMarshalerToType = reflect.TypeFor[MarshalerTo]()
jsonUnmarshalerType = reflect.TypeFor[Unmarshaler]()
jsonUnmarshalerFromType = reflect.TypeFor[UnmarshalerFrom]()
textAppenderType = reflect.TypeFor[encoding.TextAppender]()
textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]()
textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]()
allMarshalerTypes = []reflect.Type{jsonMarshalerToType, jsonMarshalerType, textAppenderType, textMarshalerType}
allUnmarshalerTypes = []reflect.Type{jsonUnmarshalerFromType, jsonUnmarshalerType, textUnmarshalerType}
allMethodTypes = append(allMarshalerTypes, allUnmarshalerTypes...)
)
// Marshaler is implemented by types that can marshal themselves.
// It is recommended that types implement [MarshalerTo] unless the implementation
// is trying to avoid a hard dependency on the "jsontext" package.
//
// It is recommended that implementations return a buffer that is safe
// for the caller to retain and potentially mutate.
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
// MarshalerTo is implemented by types that can marshal themselves.
// It is recommended that types implement MarshalerTo instead of [Marshaler]
// since this is both more performant and flexible.
// If a type implements both Marshaler and MarshalerTo,
// then MarshalerTo takes precedence. In such a case, both implementations
// should aim to have equivalent behavior for the default marshal options.
//
// The implementation must write only one JSON value to the Encoder and
// must not retain the pointer to [jsontext.Encoder].
type MarshalerTo interface {
MarshalJSONTo(*jsontext.Encoder) error
// TODO: Should users call the MarshalEncode function or
// should/can they call this method directly? Does it matter?
}
// Unmarshaler is implemented by types that can unmarshal themselves.
// It is recommended that types implement [UnmarshalerFrom] unless the implementation
// is trying to avoid a hard dependency on the "jsontext" package.
//
// The input can be assumed to be a valid encoding of a JSON value
// if called from unmarshal functionality in this package.
// UnmarshalJSON must copy the JSON data if it is retained after returning.
// It is recommended that UnmarshalJSON implement merge semantics when
// unmarshaling into a pre-populated value.
//
// Implementations must not retain or mutate the input []byte.
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
// UnmarshalerFrom is implemented by types that can unmarshal themselves.
// It is recommended that types implement UnmarshalerFrom instead of [Unmarshaler]
// since this is both more performant and flexible.
// If a type implements both Unmarshaler and UnmarshalerFrom,
// then UnmarshalerFrom takes precedence. In such a case, both implementations
// should aim to have equivalent behavior for the default unmarshal options.
//
// The implementation must read only one JSON value from the Decoder.
// It is recommended that UnmarshalJSONFrom implement merge semantics when
// unmarshaling into a pre-populated value.
//
// Implementations must not retain the pointer to [jsontext.Decoder].
type UnmarshalerFrom interface {
UnmarshalJSONFrom(*jsontext.Decoder) error
// TODO: Should users call the UnmarshalDecode function or
// should/can they call this method directly? Does it matter?
}
func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
// Avoid injecting method arshaler on the pointer or interface version
// to avoid ever calling the method on a nil pointer or interface receiver.
// Let it be injected on the value receiver (which is always addressable).
if t.Kind() == reflect.Pointer || t.Kind() == reflect.Interface {
return fncs
}
if needAddr, ok := implements(t, textMarshalerType); ok {
fncs.nonDefault = true
prevMarshal := fncs.marshal
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
(needAddr && va.forcedAddr) {
return prevMarshal(enc, va, mo)
}
marshaler := va.Addr().Interface().(encoding.TextMarshaler)
if err := export.Encoder(enc).AppendRaw('"', false, func(b []byte) ([]byte, error) {
b2, err := marshaler.MarshalText()
return append(b, b2...), err
}); err != nil {
err = wrapSkipFunc(err, "marshal method")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalText") // unlike unmarshal, always wrapped
}
if !isSemanticError(err) && !export.IsIOError(err) {
err = newMarshalErrorBefore(enc, t, err)
}
return err
}
return nil
}
}
if needAddr, ok := implements(t, textAppenderType); ok {
fncs.nonDefault = true
prevMarshal := fncs.marshal
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) (err error) {
if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
(needAddr && va.forcedAddr) {
return prevMarshal(enc, va, mo)
}
appender := va.Addr().Interface().(encoding.TextAppender)
if err := export.Encoder(enc).AppendRaw('"', false, appender.AppendText); err != nil {
err = wrapSkipFunc(err, "append method")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "AppendText") // unlike unmarshal, always wrapped
}
if !isSemanticError(err) && !export.IsIOError(err) {
err = newMarshalErrorBefore(enc, t, err)
}
return err
}
return nil
}
}
if needAddr, ok := implements(t, jsonMarshalerType); ok {
fncs.nonDefault = true
prevMarshal := fncs.marshal
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) {
return prevMarshal(enc, va, mo)
}
marshaler := va.Addr().Interface().(Marshaler)
val, err := marshaler.MarshalJSON()
if err != nil {
err = wrapSkipFunc(err, "marshal method")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped
}
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, "MarshalJSON") // unlike unmarshal, always wrapped
}
if isSyntacticError(err) {
err = newMarshalErrorBefore(enc, t, err)
}
return err
}
return nil
}
}
if needAddr, ok := implements(t, jsonMarshalerToType); ok {
fncs.nonDefault = true
prevMarshal := fncs.marshal
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) {
return prevMarshal(enc, va, mo)
}
xe := export.Encoder(enc)
prevDepth, prevLength := xe.Tokens.DepthLength()
xe.Flags.Set(jsonflags.WithinArshalCall | 1)
err := va.Addr().Interface().(MarshalerTo).MarshalJSONTo(enc)
xe.Flags.Set(jsonflags.WithinArshalCall | 0)
currDepth, currLength := xe.Tokens.DepthLength()
if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil {
err = errNonSingularValue
}
if err != nil {
err = wrapSkipFunc(err, "marshal method")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSONTo") // unlike unmarshal, always wrapped
}
if !export.IsIOError(err) {
err = newSemanticErrorWithPosition(enc, t, prevDepth, prevLength, err)
}
return err
}
return nil
}
}
if _, ok := implements(t, textUnmarshalerType); ok {
fncs.nonDefault = true
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
var flags jsonwire.ValueFlags
val, err := xd.ReadValue(&flags)
if err != nil {
return err // must be a syntactic or I/O error
}
if val.Kind() == 'n' {
if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
va.SetZero()
}
return nil
}
if val.Kind() != '"' {
return newUnmarshalErrorAfter(dec, t, errNonStringValue)
}
s := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
unmarshaler := va.Addr().Interface().(encoding.TextUnmarshaler)
if err := unmarshaler.UnmarshalText(s); err != nil {
err = wrapSkipFunc(err, "unmarshal method")
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return err // unlike marshal, never wrapped
}
if !isSemanticError(err) && !isSyntacticError(err) && !export.IsIOError(err) {
err = newUnmarshalErrorAfter(dec, t, err)
}
return err
}
return nil
}
}
if _, ok := implements(t, jsonUnmarshalerType); ok {
fncs.nonDefault = true
prevUnmarshal := fncs.unmarshal
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
if uo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
export.Decoder(dec).Tokens.Last.NeedObjectName() {
return prevUnmarshal(dec, va, uo)
}
val, err := dec.ReadValue()
if err != nil {
return err // must be a syntactic or I/O error
}
unmarshaler := va.Addr().Interface().(Unmarshaler)
if err := unmarshaler.UnmarshalJSON(val); err != nil {
err = wrapSkipFunc(err, "unmarshal method")
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return err // unlike marshal, never wrapped
}
err = newUnmarshalErrorAfter(dec, t, err)
return collapseSemanticErrors(err)
}
return nil
}
}
if _, ok := implements(t, jsonUnmarshalerFromType); ok {
fncs.nonDefault = true
prevUnmarshal := fncs.unmarshal
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
if uo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
export.Decoder(dec).Tokens.Last.NeedObjectName() {
return prevUnmarshal(dec, va, uo)
}
xd := export.Decoder(dec)
prevDepth, prevLength := xd.Tokens.DepthLength()
xd.Flags.Set(jsonflags.WithinArshalCall | 1)
err := va.Addr().Interface().(UnmarshalerFrom).UnmarshalJSONFrom(dec)
xd.Flags.Set(jsonflags.WithinArshalCall | 0)
currDepth, currLength := xd.Tokens.DepthLength()
if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil {
err = errNonSingularValue
}
if err != nil {
err = wrapSkipFunc(err, "unmarshal method")
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil {
return err2
}
return err // unlike marshal, never wrapped
}
if !isSyntacticError(err) && !export.IsIOError(err) {
err = newSemanticErrorWithPosition(dec, t, prevDepth, prevLength, err)
}
return err
}
return nil
}
}
return fncs
}
// implementsAny is like t.Implements(ifaceType) for a list of interfaces,
// but checks whether either t or reflect.PointerTo(t) implements the interface.
func implementsAny(t reflect.Type, ifaceTypes ...reflect.Type) bool {
for _, ifaceType := range ifaceTypes {
if _, ok := implements(t, ifaceType); ok {
return true
}
}
return false
}
// implements is like t.Implements(ifaceType) but checks whether
// either t or reflect.PointerTo(t) implements the interface.
// It also reports whether the value needs to be addressed
// in order to satisfy the interface.
func implements(t, ifaceType reflect.Type) (needAddr, ok bool) {
switch {
case t.Implements(ifaceType):
return false, true
case reflect.PointerTo(t).Implements(ifaceType):
return true, true
default:
return false, false
}
}