aboutsummaryrefslogtreecommitdiff
path: root/src/encoding
diff options
context:
space:
mode:
Diffstat (limited to 'src/encoding')
-rw-r--r--src/encoding/json/v2/arshal.go4
-rw-r--r--src/encoding/json/v2/arshal_funcs.go49
-rw-r--r--src/encoding/json/v2/arshal_methods.go14
-rw-r--r--src/encoding/json/v2/arshal_test.go107
-rw-r--r--src/encoding/json/v2/errors.go7
-rw-r--r--src/encoding/json/v2/example_test.go8
6 files changed, 96 insertions, 93 deletions
diff --git a/src/encoding/json/v2/arshal.go b/src/encoding/json/v2/arshal.go
index 5537a467d8..180a935c52 100644
--- a/src/encoding/json/v2/arshal.go
+++ b/src/encoding/json/v2/arshal.go
@@ -50,7 +50,7 @@ var export = jsontext.Internal.Export(&internal.AllowInternalUse)
//
// - If any type-specific functions in a [WithMarshalers] option match
// the value type, then those functions are called to encode the value.
-// If all applicable functions return [SkipFunc],
+// If all applicable functions return [errors.ErrUnsupported],
// then the value is encoded according to subsequent rules.
//
// - If the value type implements [MarshalerTo],
@@ -265,7 +265,7 @@ func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err erro
//
// - If any type-specific functions in a [WithUnmarshalers] option match
// the value type, then those functions are called to decode the JSON
-// value. If all applicable functions return [SkipFunc],
+// value. If all applicable functions return [errors.ErrUnsupported],
// then the input is decoded according to subsequent rules.
//
// - If the value type implements [UnmarshalerFrom],
diff --git a/src/encoding/json/v2/arshal_funcs.go b/src/encoding/json/v2/arshal_funcs.go
index 28916af948..1c325b16cb 100644
--- a/src/encoding/json/v2/arshal_funcs.go
+++ b/src/encoding/json/v2/arshal_funcs.go
@@ -26,9 +26,11 @@ import (
// For example, it is permissible to call [jsontext.Decoder.PeekKind],
// but not permissible to call [jsontext.Decoder.ReadToken] or
// [jsontext.Encoder.WriteToken] since such methods mutate the state.
-var SkipFunc = errors.New("json: skip function")
+//
+// Deprecated: Use [errors.ErrUnsupported] instead.
+var SkipFunc = errors.ErrUnsupported
-var errSkipMutation = errors.New("must not read or write any tokens when skipping")
+var errUnsupportedMutation = errors.New("unsupported calls must not read or write any tokens")
var errNonSingularValue = errors.New("must read or write exactly one value")
// Marshalers is a list of functions that may override the marshal behavior
@@ -41,7 +43,8 @@ type Marshalers = typedMarshalers
// JoinMarshalers constructs a flattened list of marshal functions.
// If multiple functions in the list are applicable for a value of a given type,
// then those earlier in the list take precedence over those that come later.
-// If a function returns [SkipFunc], then the next applicable function is called,
+// If a function returns [errors.ErrUnsupported],
+// then the next applicable function is called,
// otherwise the default marshaling behavior is used.
//
// For example:
@@ -63,7 +66,8 @@ type Unmarshalers = typedUnmarshalers
// JoinUnmarshalers constructs a flattened list of unmarshal functions.
// If multiple functions in the list are applicable for a value of a given type,
// then those earlier in the list take precedence over those that come later.
-// If a function returns [SkipFunc], then the next applicable function is called,
+// If a function returns [errors.ErrUnsupported],
+// then the next applicable function is called,
// otherwise the default unmarshaling behavior is used.
//
// For example:
@@ -151,7 +155,7 @@ func (a *typedArshalers[Coder]) lookup(fnc func(*Coder, addressableValue, *jsono
fncDefault := fnc
fnc = func(c *Coder, v addressableValue, o *jsonopts.Struct) error {
for _, fnc := range fncs {
- if err := fnc(c, v, o); err != SkipFunc {
+ if err := fnc(c, v, o); !errors.Is(err, errors.ErrUnsupported) {
return err // may be nil or non-nil
}
}
@@ -171,7 +175,7 @@ func (a *typedArshalers[Coder]) lookup(fnc func(*Coder, addressableValue, *jsono
//
// The function must marshal exactly one JSON value.
// The value of T must not be retained outside the function call.
-// It may not return [SkipFunc].
+// It may not return [errors.ErrUnsupported].
func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers {
t := reflect.TypeFor[T]()
assertCastableTo(t, true)
@@ -181,7 +185,7 @@ func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers {
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)")
+ err = wrapErrUnsupported(err, "marshal function of type func(T) ([]byte, error)")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalFunc") // unlike unmarshal, always wrapped
}
@@ -210,9 +214,9 @@ func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers {
// if T is an interface or pointer type.
//
// The function must marshal exactly one JSON value by calling write methods
-// on the provided encoder. It may return [SkipFunc] such that marshaling can
+// on the provided encoder. It may return [errors.ErrUnsupported] such that marshaling can
// move on to the next marshal function. However, no mutable method calls may
-// be called on the encoder if [SkipFunc] is returned.
+// be called on the encoder if [errors.ErrUnsupported] is returned.
// The pointer to [jsontext.Encoder] and the value of T
// must not be retained outside the function call.
func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers {
@@ -232,11 +236,11 @@ func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers {
err = errNonSingularValue
}
if err != nil {
- if err == SkipFunc {
+ if errors.Is(err, errors.ErrUnsupported) {
if prevDepth == currDepth && prevLength == currLength {
- return SkipFunc
+ return err // forward [errors.ErrUnsupported]
}
- err = errSkipMutation
+ err = errUnsupportedMutation
}
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalToFunc") // unlike unmarshal, always wrapped
@@ -261,7 +265,7 @@ func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers {
// The function must unmarshal exactly one JSON value.
// The input []byte must not be mutated.
// The input []byte and value T must not be retained outside the function call.
-// It may not return [SkipFunc].
+// It may not return [errors.ErrUnsupported].
func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers {
t := reflect.TypeFor[T]()
assertCastableTo(t, false)
@@ -275,7 +279,7 @@ func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers {
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")
+ err = wrapErrUnsupported(err, "unmarshal function of type func([]byte, T) error")
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return err // unlike marshal, never wrapped
}
@@ -294,9 +298,9 @@ func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers {
// The function is always provided with a non-nil pointer value.
//
// The function must unmarshal exactly one JSON value by calling read methods
-// on the provided decoder. It may return [SkipFunc] such that unmarshaling can
+// on the provided decoder. It may return [errors.ErrUnsupported] such that unmarshaling can
// move on to the next unmarshal function. However, no mutable method calls may
-// be called on the decoder if [SkipFunc] is returned.
+// be called on the decoder if [errors.ErrUnsupported] is returned.
// The pointer to [jsontext.Decoder] and the value of T
// must not be retained outside the function call.
func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers {
@@ -319,11 +323,11 @@ func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers
err = errNonSingularValue
}
if err != nil {
- if err == SkipFunc {
+ if errors.Is(err, errors.ErrUnsupported) {
if prevDepth == currDepth && prevLength == currLength {
- return SkipFunc
+ return err // forward [errors.ErrUnsupported]
}
- err = errSkipMutation
+ err = errUnsupportedMutation
}
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil {
@@ -431,10 +435,3 @@ func castableToFromAny(to reflect.Type) bool {
}
return false
}
-
-func wrapSkipFunc(err error, what string) error {
- if err == SkipFunc {
- return errors.New(what + " cannot be skipped")
- }
- return err
-}
diff --git a/src/encoding/json/v2/arshal_methods.go b/src/encoding/json/v2/arshal_methods.go
index 1621eadc08..ed65ed7632 100644
--- a/src/encoding/json/v2/arshal_methods.go
+++ b/src/encoding/json/v2/arshal_methods.go
@@ -135,7 +135,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
b2, err := marshaler.MarshalText()
return append(b, b2...), err
}); err != nil {
- err = wrapSkipFunc(err, "marshal method")
+ err = wrapErrUnsupported(err, "MarshalText method")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalText") // unlike unmarshal, always wrapped
}
@@ -158,7 +158,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
}
appender, _ := reflect.TypeAssert[encoding.TextAppender](va.Addr())
if err := export.Encoder(enc).AppendRaw('"', false, appender.AppendText); err != nil {
- err = wrapSkipFunc(err, "append method")
+ err = wrapErrUnsupported(err, "AppendText method")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "AppendText") // unlike unmarshal, always wrapped
}
@@ -182,7 +182,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
marshaler, _ := reflect.TypeAssert[Marshaler](va.Addr())
val, err := marshaler.MarshalJSON()
if err != nil {
- err = wrapSkipFunc(err, "marshal method")
+ err = wrapErrUnsupported(err, "MarshalJSON method")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped
}
@@ -221,7 +221,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
err = errNonSingularValue
}
if err != nil {
- err = wrapSkipFunc(err, "marshal method")
+ err = wrapErrUnsupported(err, "MarshalJSONTo method")
if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSONTo") // unlike unmarshal, always wrapped
}
@@ -255,7 +255,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
s := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
unmarshaler, _ := reflect.TypeAssert[encoding.TextUnmarshaler](va.Addr())
if err := unmarshaler.UnmarshalText(s); err != nil {
- err = wrapSkipFunc(err, "unmarshal method")
+ err = wrapErrUnsupported(err, "UnmarshalText method")
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return err // unlike marshal, never wrapped
}
@@ -282,7 +282,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
}
unmarshaler, _ := reflect.TypeAssert[Unmarshaler](va.Addr())
if err := unmarshaler.UnmarshalJSON(val); err != nil {
- err = wrapSkipFunc(err, "unmarshal method")
+ err = wrapErrUnsupported(err, "UnmarshalJSON method")
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return err // unlike marshal, never wrapped
}
@@ -315,7 +315,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
err = errNonSingularValue
}
if err != nil {
- err = wrapSkipFunc(err, "unmarshal method")
+ err = wrapErrUnsupported(err, "UnmarshalJSONFrom method")
if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil {
return err2
diff --git a/src/encoding/json/v2/arshal_test.go b/src/encoding/json/v2/arshal_test.go
index 1a7ed4b886..e8a9e79217 100644
--- a/src/encoding/json/v2/arshal_test.go
+++ b/src/encoding/json/v2/arshal_test.go
@@ -3393,11 +3393,11 @@ func TestMarshal(t *testing.T) {
want: `nullnull`,
wantErr: EM(errNonSingularValue).withPos(`nullnull`, "").withType(0, T[marshalJSONv2Func]()),
}, {
- name: jsontest.Name("Methods/Invalid/JSONv2/SkipFunc"),
+ name: jsontest.Name("Methods/Invalid/JSONv2/ErrUnsupported"),
in: marshalJSONv2Func(func(enc *jsontext.Encoder) error {
- return SkipFunc
+ return errors.ErrUnsupported
}),
- wantErr: EM(errors.New("marshal method cannot be skipped")).withType(0, T[marshalJSONv2Func]()),
+ wantErr: EM(errors.New("MarshalJSONTo method may not return errors.ErrUnsupported")).withType(0, T[marshalJSONv2Func]()),
}, {
name: jsontest.Name("Methods/Invalid/JSONv1/Error"),
in: marshalJSONv1Func(func() ([]byte, error) {
@@ -3411,11 +3411,11 @@ func TestMarshal(t *testing.T) {
}),
wantErr: EM(newInvalidCharacterError("i", "at start of value", 0, "")).withType(0, T[marshalJSONv1Func]()),
}, {
- name: jsontest.Name("Methods/Invalid/JSONv1/SkipFunc"),
+ name: jsontest.Name("Methods/Invalid/JSONv1/ErrUnsupported"),
in: marshalJSONv1Func(func() ([]byte, error) {
- return nil, SkipFunc
+ return nil, errors.ErrUnsupported
}),
- wantErr: EM(errors.New("marshal method cannot be skipped")).withType(0, T[marshalJSONv1Func]()),
+ wantErr: EM(errors.New("MarshalJSON method may not return errors.ErrUnsupported")).withType(0, T[marshalJSONv1Func]()),
}, {
name: jsontest.Name("Methods/AppendText"),
in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "hello"...), nil }),
@@ -3457,11 +3457,11 @@ func TestMarshal(t *testing.T) {
}),
want: "\"\xde\xad\ufffd\ufffd\"",
}, {
- name: jsontest.Name("Methods/Invalid/Text/SkipFunc"),
+ name: jsontest.Name("Methods/Invalid/Text/ErrUnsupported"),
in: marshalTextFunc(func() ([]byte, error) {
- return nil, SkipFunc
+ return nil, errors.ErrUnsupported
}),
- wantErr: EM(wrapSkipFunc(SkipFunc, "marshal method")).withType(0, T[marshalTextFunc]()),
+ wantErr: EM(wrapErrUnsupported(errors.ErrUnsupported, "MarshalText method")).withType(0, T[marshalTextFunc]()),
}, {
name: jsontest.Name("Methods/Invalid/MapKey/JSONv2/Syntax"),
in: map[any]string{
@@ -3586,11 +3586,11 @@ func TestMarshal(t *testing.T) {
name: jsontest.Name("Functions/Bool/V1/SkipError"),
opts: []Options{
WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
- return nil, SkipFunc
+ return nil, errors.ErrUnsupported
})),
},
in: true,
- wantErr: EM(wrapSkipFunc(SkipFunc, "marshal function of type func(T) ([]byte, error)")).withType(0, T[bool]()),
+ wantErr: EM(wrapErrUnsupported(errors.ErrUnsupported, "marshal function of type func(T) ([]byte, error)")).withType(0, T[bool]()),
}, {
name: jsontest.Name("Functions/Bool/V1/InvalidValue"),
opts: []Options{
@@ -3634,7 +3634,7 @@ func TestMarshal(t *testing.T) {
name: jsontest.Name("Functions/Bool/V2/Skipped"),
opts: []Options{
WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
- return SkipFunc
+ return errors.ErrUnsupported
})),
},
in: true,
@@ -3644,21 +3644,21 @@ func TestMarshal(t *testing.T) {
opts: []Options{
WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
enc.WriteValue([]byte(`"hello"`))
- return SkipFunc
+ return errors.ErrUnsupported
})),
},
in: true,
want: `"hello"`,
- wantErr: EM(errSkipMutation).withPos(`"hello"`, "").withType(0, T[bool]()),
+ wantErr: EM(errUnsupportedMutation).withPos(`"hello"`, "").withType(0, T[bool]()),
}, {
- name: jsontest.Name("Functions/Bool/V2/WrappedSkipError"),
+ name: jsontest.Name("Functions/Bool/V2/WrappedUnsupportedError"),
opts: []Options{
WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
- return fmt.Errorf("wrap: %w", SkipFunc)
+ return fmt.Errorf("wrap: %w", errors.ErrUnsupported)
})),
},
- in: true,
- wantErr: EM(fmt.Errorf("wrap: %w", SkipFunc)).withType(0, T[bool]()),
+ in: true,
+ want: `true`,
}, {
name: jsontest.Name("Functions/Map/Key/NoCaseString/V1"),
opts: []Options{
@@ -4021,7 +4021,7 @@ func TestMarshal(t *testing.T) {
return err
}
}
- return SkipFunc
+ return errors.ErrUnsupported
}
makeValueChecker := func(name string, want []PV) func(e *jsontext.Encoder, v any) error {
checkNext := func(e *jsontext.Encoder, v any) error {
@@ -4038,7 +4038,7 @@ func TestMarshal(t *testing.T) {
return fmt.Errorf("%s:\n\tgot %#v\n\twant %#v", name, pv, want[0])
default:
want = want[1:]
- return SkipFunc
+ return errors.ErrUnsupported
}
}
lastChecks = append(lastChecks, func() error {
@@ -4060,7 +4060,7 @@ func TestMarshal(t *testing.T) {
return fmt.Errorf("%s: got %v, want %v", name, p, want[0])
default:
want = want[1:]
- return SkipFunc
+ return errors.ErrUnsupported
}
}
lastChecks = append(lastChecks, func() error {
@@ -4242,7 +4242,7 @@ func TestMarshal(t *testing.T) {
opts: []Options{
WithMarshalers(JoinMarshalers(
MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
- return SkipFunc
+ return errors.ErrUnsupported
}),
MarshalFunc(func(bool) ([]byte, error) {
return []byte(`"called"`), nil
@@ -7800,12 +7800,12 @@ func TestUnmarshal(t *testing.T) {
})),
wantErr: EU(errNonSingularValue).withPos(`{}`, "").withType(0, T[unmarshalJSONv2Func]()),
}, {
- name: jsontest.Name("Methods/Invalid/JSONv2/SkipFunc"),
+ name: jsontest.Name("Methods/Invalid/JSONv2/ErrUnsupported"),
inBuf: `{}`,
inVal: addr(unmarshalJSONv2Func(func(*jsontext.Decoder) error {
- return SkipFunc
+ return errors.ErrUnsupported
})),
- wantErr: EU(wrapSkipFunc(SkipFunc, "unmarshal method")).withType(0, T[unmarshalJSONv2Func]()),
+ wantErr: EU(wrapErrUnsupported(errors.ErrUnsupported, "UnmarshalJSONFrom method")).withType(0, T[unmarshalJSONv2Func]()),
}, {
name: jsontest.Name("Methods/Invalid/JSONv1/Error"),
inBuf: `{}`,
@@ -7814,12 +7814,12 @@ func TestUnmarshal(t *testing.T) {
})),
wantErr: EU(errSomeError).withType('{', T[unmarshalJSONv1Func]()),
}, {
- name: jsontest.Name("Methods/Invalid/JSONv1/SkipFunc"),
+ name: jsontest.Name("Methods/Invalid/JSONv1/ErrUnsupported"),
inBuf: `{}`,
inVal: addr(unmarshalJSONv1Func(func([]byte) error {
- return SkipFunc
+ return errors.ErrUnsupported
})),
- wantErr: EU(wrapSkipFunc(SkipFunc, "unmarshal method")).withType('{', T[unmarshalJSONv1Func]()),
+ wantErr: EU(wrapErrUnsupported(errors.ErrUnsupported, "UnmarshalJSON method")).withType('{', T[unmarshalJSONv1Func]()),
}, {
name: jsontest.Name("Methods/Invalid/Text/Error"),
inBuf: `"value"`,
@@ -7835,12 +7835,12 @@ func TestUnmarshal(t *testing.T) {
})),
wantErr: EU(errNonStringValue).withType('{', T[unmarshalTextFunc]()),
}, {
- name: jsontest.Name("Methods/Invalid/Text/SkipFunc"),
+ name: jsontest.Name("Methods/Invalid/Text/ErrUnsupported"),
inBuf: `"value"`,
inVal: addr(unmarshalTextFunc(func([]byte) error {
- return SkipFunc
+ return errors.ErrUnsupported
})),
- wantErr: EU(wrapSkipFunc(SkipFunc, "unmarshal method")).withType('"', T[unmarshalTextFunc]()),
+ wantErr: EU(wrapErrUnsupported(errors.ErrUnsupported, "UnmarshalText method")).withType('"', T[unmarshalTextFunc]()),
}, {
name: jsontest.Name("Functions/String/V1"),
opts: []Options{
@@ -7960,13 +7960,13 @@ func TestUnmarshal(t *testing.T) {
name: jsontest.Name("Functions/String/V1/SkipError"),
opts: []Options{
WithUnmarshalers(UnmarshalFunc(func([]byte, *string) error {
- return SkipFunc
+ return errors.ErrUnsupported
})),
},
inBuf: `""`,
inVal: addr(""),
want: addr(""),
- wantErr: EU(wrapSkipFunc(SkipFunc, "unmarshal function of type func([]byte, T) error")).withType('"', reflect.PointerTo(stringType)),
+ wantErr: EU(wrapErrUnsupported(errors.ErrUnsupported, "unmarshal function of type func([]byte, T) error")).withType('"', reflect.PointerTo(stringType)),
}, {
name: jsontest.Name("Functions/String/V2/DirectError"),
opts: []Options{
@@ -8010,7 +8010,7 @@ func TestUnmarshal(t *testing.T) {
name: jsontest.Name("Functions/String/V2/Skipped"),
opts: []Options{
WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
- return SkipFunc
+ return errors.ErrUnsupported
})),
},
inBuf: `""`,
@@ -8023,24 +8023,23 @@ func TestUnmarshal(t *testing.T) {
if _, err := dec.ReadValue(); err != nil {
return err
}
- return SkipFunc
+ return errors.ErrUnsupported
})),
},
inBuf: `""`,
inVal: addr(""),
want: addr(""),
- wantErr: EU(errSkipMutation).withType(0, reflect.PointerTo(stringType)),
+ wantErr: EU(errUnsupportedMutation).withType(0, reflect.PointerTo(stringType)),
}, {
- name: jsontest.Name("Functions/String/V2/WrappedSkipError"),
+ name: jsontest.Name("Functions/String/V2/WrappedUnsupported"),
opts: []Options{
WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
- return fmt.Errorf("wrap: %w", SkipFunc)
+ return fmt.Errorf("wrap: %w", errors.ErrUnsupported)
})),
},
- inBuf: `""`,
- inVal: addr(""),
- want: addr(""),
- wantErr: EU(fmt.Errorf("wrap: %w", SkipFunc)).withType(0, reflect.PointerTo(stringType)),
+ inBuf: `""`,
+ inVal: addr(""),
+ want: addr(""),
}, {
name: jsontest.Name("Functions/Map/Key/NoCaseString/V1"),
opts: []Options{
@@ -8307,7 +8306,7 @@ func TestUnmarshal(t *testing.T) {
opts: []Options{
WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
*v = net.IP{}
- return SkipFunc
+ return errors.ErrUnsupported
})),
},
inBuf: `{"X":"1.1.1.1"}`,
@@ -8318,7 +8317,7 @@ func TestUnmarshal(t *testing.T) {
opts: []Options{
WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
*v = new(net.IP)
- return SkipFunc
+ return errors.ErrUnsupported
})),
},
inBuf: `{"X":"1.1.1.1"}`,
@@ -8329,7 +8328,7 @@ func TestUnmarshal(t *testing.T) {
opts: []Options{
WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
*v = (*net.IP)(nil)
- return SkipFunc
+ return errors.ErrUnsupported
})),
},
inBuf: `{"X":"1.1.1.1"}`,
@@ -8341,7 +8340,7 @@ func TestUnmarshal(t *testing.T) {
WithUnmarshalers(JoinUnmarshalers(
UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
*v = (*net.IP)(nil)
- return SkipFunc
+ return errors.ErrUnsupported
}),
UnmarshalFunc(func(b []byte, v *net.IP) error {
b = bytes.ReplaceAll(b, []byte(`1`), []byte(`8`))
@@ -8389,7 +8388,7 @@ func TestUnmarshal(t *testing.T) {
return err
}
}
- return SkipFunc
+ return errors.ErrUnsupported
}
makeValueChecker := func(name string, want []PV) func(d *jsontext.Decoder, v any) error {
checkNext := func(d *jsontext.Decoder, v any) error {
@@ -8406,7 +8405,7 @@ func TestUnmarshal(t *testing.T) {
return fmt.Errorf("%s:\n\tgot %#v\n\twant %#v", name, pv, want[0])
default:
want = want[1:]
- return SkipFunc
+ return errors.ErrUnsupported
}
}
lastChecks = append(lastChecks, func() error {
@@ -8428,7 +8427,7 @@ func TestUnmarshal(t *testing.T) {
return fmt.Errorf("%s: got %v, want %v", name, p, want[0])
default:
want = want[1:]
- return SkipFunc
+ return errors.ErrUnsupported
}
}
lastChecks = append(lastChecks, func() error {
@@ -8622,7 +8621,7 @@ func TestUnmarshal(t *testing.T) {
opts: []Options{
WithUnmarshalers(JoinUnmarshalers(
UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
- return SkipFunc
+ return errors.ErrUnsupported
}),
UnmarshalFunc(func(b []byte, v *string) error {
if string(b) != `"called"` {
@@ -9350,7 +9349,7 @@ func TestUnmarshalDecodeOptions(t *testing.T) {
}
calledFuncs++
calledOptions = opts
- return SkipFunc
+ return errors.ErrUnsupported
})), // unmarshal-specific option; only relevant for UnmarshalDecode
)
@@ -9389,7 +9388,7 @@ func TestUnmarshalDecodeOptions(t *testing.T) {
t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
}
calledFuncs = math.MaxInt
- return SkipFunc
+ return errors.ErrUnsupported
})), // should override
)); err != nil {
t.Fatalf("UnmarshalDecode: %v", err)
@@ -9489,7 +9488,7 @@ func TestMarshalEncodeOptions(t *testing.T) {
}
calledFuncs++
calledOptions = opts
- return SkipFunc
+ return errors.ErrUnsupported
})), // marshal-specific option; only relevant for MarshalEncode
)
@@ -9528,7 +9527,7 @@ func TestMarshalEncodeOptions(t *testing.T) {
t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
}
calledFuncs = math.MaxInt
- return SkipFunc
+ return errors.ErrUnsupported
})), // should override
)); err != nil {
t.Fatalf("MarshalEncode: %v", err)
diff --git a/src/encoding/json/v2/errors.go b/src/encoding/json/v2/errors.go
index 4895386fe2..da50bc30fc 100644
--- a/src/encoding/json/v2/errors.go
+++ b/src/encoding/json/v2/errors.go
@@ -299,6 +299,13 @@ func collapseSemanticErrors(err error) error {
return err
}
+func wrapErrUnsupported(err error, what string) error {
+ if errors.Is(err, errors.ErrUnsupported) {
+ return errors.New(what + " may not return errors.ErrUnsupported")
+ }
+ return err
+}
+
// errorModalVerb is a modal verb like "cannot" or "unable to".
//
// Once per process, Hyrum-proof the error message by deliberately
diff --git a/src/encoding/json/v2/example_test.go b/src/encoding/json/v2/example_test.go
index 684ca9c6a2..b95ad0f73c 100644
--- a/src/encoding/json/v2/example_test.go
+++ b/src/encoding/json/v2/example_test.go
@@ -550,8 +550,8 @@ func ExampleWithUnmarshalers_rawNumber() {
if dec.PeekKind() == '0' {
*val = jsontext.Value(nil)
}
- // Return SkipFunc to fallback on default unmarshal behavior.
- return json.SkipFunc
+ // Return ErrUnsupported to fallback on default unmarshal behavior.
+ return errors.ErrUnsupported
}),
))
if err != nil {
@@ -604,8 +604,8 @@ func ExampleWithUnmarshalers_recordOffsets() {
n := len(unread) - len(bytes.TrimLeft(unread, " \n\r\t,:"))
tunnel.ByteOffset = dec.InputOffset() + int64(n)
- // Return SkipFunc to fallback on default unmarshal behavior.
- return json.SkipFunc
+ // Return ErrUnsupported to fallback on default unmarshal behavior.
+ return errors.ErrUnsupported
}),
))
if err != nil {