Move error types to internal/errors package

This commit is contained in:
Masaaki Goshima 2021-03-13 13:31:14 +09:00
parent 7c0a056064
commit 377d0b0dfc
8 changed files with 212 additions and 241 deletions

View File

@ -140,7 +140,7 @@ func (d *floatDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
str := *(*string)(unsafe.Pointer(&bytes))
f64, err := strconv.ParseFloat(str, 64)
if err != nil {
return &SyntaxError{msg: err.Error(), Offset: s.totalOffset()}
return errSyntax(err.Error(), s.totalOffset())
}
d.op(p, f64)
return nil
@ -161,7 +161,7 @@ func (d *floatDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
s := *(*string)(unsafe.Pointer(&bytes))
f64, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, &SyntaxError{msg: err.Error(), Offset: cursor}
return 0, errSyntax(err.Error(), cursor)
}
d.op(p, f64)
return cursor, nil

View File

@ -27,7 +27,7 @@ func (d *numberDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) e
return err
}
if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil {
return &SyntaxError{msg: err.Error(), Offset: s.totalOffset()}
return errSyntax(err.Error(), s.totalOffset())
}
d.op(p, Number(string(bytes)))
s.reset()
@ -40,7 +40,7 @@ func (d *numberDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer
return 0, err
}
if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil {
return 0, &SyntaxError{msg: err.Error(), Offset: c}
return 0, errSyntax(err.Error(), c)
}
cursor = c
s := *(*string)(unsafe.Pointer(&bytes))

View File

@ -61,7 +61,7 @@ func errUnsupportedFloat(v float64) *UnsupportedValueError {
}
}
func errMarshaler(code *opcode, err error) *MarshalerError {
func errMarshalerWithCode(code *opcode, err error) *MarshalerError {
return &MarshalerError{
Type: rtype2type(code.typ),
Err: err,

View File

@ -2,11 +2,9 @@ package json
import (
"bytes"
"encoding"
"fmt"
"math"
"reflect"
"runtime"
"sort"
"strings"
"unsafe"
@ -142,65 +140,32 @@ func encodeRunEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode
b = bb
code = code.next
case opMarshalJSON:
ptr := load(ctxptr, code.idx)
if ptr == 0 {
p := load(ctxptr, code.idx)
if p == 0 {
b = encodeNull(b)
b = encodeIndentComma(b)
code = code.next
break
}
v := ptrToInterface(code, ptr)
bb, err := v.(Marshaler).MarshalJSON()
bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true)
if err != nil {
return nil, errMarshaler(code, err)
}
runtime.KeepAlive(v)
if len(bb) == 0 {
return nil, errUnexpectedEndOfJSON(
fmt.Sprintf("error calling MarshalJSON for type %s", code.typ),
0,
)
}
var compactBuf bytes.Buffer
if err := compact(&compactBuf, bb, true); err != nil {
return nil, err
}
var indentBuf bytes.Buffer
if err := encodeWithIndent(
&indentBuf,
compactBuf.Bytes(),
string(ctx.prefix)+strings.Repeat(string(ctx.indentStr), ctx.baseIndent+code.indent),
string(ctx.indentStr),
); err != nil {
return nil, err
}
b = append(b, indentBuf.Bytes()...)
b = encodeIndentComma(b)
b = encodeIndentComma(bb)
code = code.next
case opMarshalText:
ptr := load(ctxptr, code.idx)
isPtr := code.typ.Kind() == reflect.Ptr
p := ptrToUnsafePtr(ptr)
if p == nil {
b = encodeNull(b)
b = encodeIndentComma(b)
} else if isPtr && *(*unsafe.Pointer)(p) == nil {
b = append(b, '"', '"', ',', '\n')
} else {
if isPtr && code.typ.Elem().Implements(marshalTextType) {
p = *(*unsafe.Pointer)(p)
}
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
typ: code.typ,
ptr: p,
}))
bytes, err := v.(encoding.TextMarshaler).MarshalText()
if err != nil {
return nil, errMarshaler(code, err)
}
b = encodeEscapedString(b, *(*string)(unsafe.Pointer(&bytes)))
p := load(ctxptr, code.idx)
if p == 0 {
b = append(b, `""`...)
b = encodeIndentComma(b)
code = code.next
break
}
bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true)
if err != nil {
return nil, err
}
b = encodeIndentComma(bb)
code = code.next
case opSlice:
p := load(ctxptr, code.idx)

View File

@ -2,11 +2,9 @@ package json
import (
"bytes"
"encoding"
"fmt"
"math"
"reflect"
"runtime"
"sort"
"strings"
"unsafe"
@ -142,65 +140,32 @@ func encodeRunIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, op
b = bb
code = code.next
case opMarshalJSON:
ptr := load(ctxptr, code.idx)
if ptr == 0 {
p := load(ctxptr, code.idx)
if p == 0 {
b = encodeNull(b)
b = encodeIndentComma(b)
code = code.next
break
}
v := ptrToInterface(code, ptr)
bb, err := v.(Marshaler).MarshalJSON()
bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false)
if err != nil {
return nil, errMarshaler(code, err)
}
runtime.KeepAlive(v)
if len(bb) == 0 {
return nil, errUnexpectedEndOfJSON(
fmt.Sprintf("error calling MarshalJSON for type %s", code.typ),
0,
)
}
var compactBuf bytes.Buffer
if err := compact(&compactBuf, bb, false); err != nil {
return nil, err
}
var indentBuf bytes.Buffer
if err := encodeWithIndent(
&indentBuf,
compactBuf.Bytes(),
string(ctx.prefix)+strings.Repeat(string(ctx.indentStr), ctx.baseIndent+code.indent),
string(ctx.indentStr),
); err != nil {
return nil, err
}
b = append(b, indentBuf.Bytes()...)
b = encodeIndentComma(b)
b = encodeIndentComma(bb)
code = code.next
case opMarshalText:
ptr := load(ctxptr, code.idx)
isPtr := code.typ.Kind() == reflect.Ptr
p := ptrToUnsafePtr(ptr)
if p == nil {
b = encodeNull(b)
b = encodeIndentComma(b)
} else if isPtr && *(*unsafe.Pointer)(p) == nil {
b = append(b, '"', '"', ',', '\n')
} else {
if isPtr && code.typ.Elem().Implements(marshalTextType) {
p = *(*unsafe.Pointer)(p)
}
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
typ: code.typ,
ptr: p,
}))
bytes, err := v.(encoding.TextMarshaler).MarshalText()
if err != nil {
return nil, errMarshaler(code, err)
}
b = encodeNoEscapedString(b, *(*string)(unsafe.Pointer(&bytes)))
p := load(ctxptr, code.idx)
if p == 0 {
b = append(b, `""`...)
b = encodeIndentComma(b)
code = code.next
break
}
bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false)
if err != nil {
return nil, err
}
b = encodeIndentComma(bb)
code = code.next
case opSlice:
p := load(ctxptr, code.idx)

140
error.go
View File

@ -1,9 +1,7 @@
package json
import (
"fmt"
"reflect"
"strconv"
"github.com/goccy/go-json/internal/errors"
)
// Before Go 1.2, an InvalidUTF8Error was returned by Marshal when
@ -12,142 +10,40 @@ import (
// replacing invalid bytes with the Unicode replacement rune U+FFFD.
//
// Deprecated: No longer used; kept for compatibility.
type InvalidUTF8Error struct {
S string // the whole string value that caused the error
}
func (e *InvalidUTF8Error) Error() string {
return fmt.Sprintf("json: invalid UTF-8 in string: %s", strconv.Quote(e.S))
}
type InvalidUTF8Error = errors.InvalidUTF8Error
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
// (The argument to Unmarshal must be a non-nil pointer.)
type InvalidUnmarshalError struct {
Type reflect.Type
}
func (e *InvalidUnmarshalError) Error() string {
if e.Type == nil {
return "json: Unmarshal(nil)"
}
if e.Type.Kind() != reflect.Ptr {
return fmt.Sprintf("json: Unmarshal(non-pointer %s)", e.Type)
}
return fmt.Sprintf("json: Unmarshal(nil %s)", e.Type)
}
type InvalidUnmarshalError = errors.InvalidUnmarshalError
// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method.
type MarshalerError struct {
Type reflect.Type
Err error
sourceFunc string
}
func (e *MarshalerError) Error() string {
srcFunc := e.sourceFunc
if srcFunc == "" {
srcFunc = "MarshalJSON"
}
return fmt.Sprintf("json: error calling %s for type %s: %s", srcFunc, e.Type, e.Err.Error())
}
// Unwrap returns the underlying error.
func (e *MarshalerError) Unwrap() error { return e.Err }
type MarshalerError = errors.MarshalerError
// A SyntaxError is a description of a JSON syntax error.
type SyntaxError struct {
msg string // description of error
Offset int64 // error occurred after reading Offset bytes
}
func (e *SyntaxError) Error() string { return e.msg }
type SyntaxError = errors.SyntaxError
// An UnmarshalFieldError describes a JSON object key that
// led to an unexported (and therefore unwritable) struct field.
//
// Deprecated: No longer used; kept for compatibility.
type UnmarshalFieldError struct {
Key string
Type reflect.Type
Field reflect.StructField
}
func (e *UnmarshalFieldError) Error() string {
return fmt.Sprintf("json: cannot unmarshal object key %s into unexported field %s of type %s",
strconv.Quote(e.Key), e.Field.Name, e.Type.String(),
)
}
type UnmarshalFieldError = errors.UnmarshalFieldError
// An UnmarshalTypeError describes a JSON value that was
// not appropriate for a value of a specific Go type.
type UnmarshalTypeError struct {
Value string // description of JSON value - "bool", "array", "number -5"
Type reflect.Type // type of Go value it could not be assigned to
Offset int64 // error occurred after reading Offset bytes
Struct string // name of the struct type containing the field
Field string // the full path from root node to the field
}
func (e *UnmarshalTypeError) Error() string {
if e.Struct != "" || e.Field != "" {
return fmt.Sprintf("json: cannot unmarshal %s into Go struct field %s.%s of type %s",
e.Value, e.Struct, e.Field, e.Type,
)
}
return fmt.Sprintf("json: cannot unmarshal %s into Go value of type %s", e.Value, e.Type)
}
type UnmarshalTypeError = errors.UnmarshalTypeError
// An UnsupportedTypeError is returned by Marshal when attempting
// to encode an unsupported value type.
type UnsupportedTypeError struct {
Type reflect.Type
}
type UnsupportedTypeError = errors.UnsupportedTypeError
func (e *UnsupportedTypeError) Error() string {
return fmt.Sprintf("json: unsupported type: %s", e.Type)
}
type UnsupportedValueError = errors.UnsupportedValueError
type UnsupportedValueError struct {
Value reflect.Value
Str string
}
func (e *UnsupportedValueError) Error() string {
return fmt.Sprintf("json: unsupported value: %s", e.Str)
}
func errExceededMaxDepth(c byte, cursor int64) *SyntaxError {
return &SyntaxError{
msg: fmt.Sprintf(`invalid character "%c" exceeded max depth`, c),
Offset: cursor,
}
}
func errNotAtBeginningOfValue(cursor int64) *SyntaxError {
return &SyntaxError{msg: "not at beginning of value", Offset: cursor}
}
func errUnexpectedEndOfJSON(msg string, cursor int64) *SyntaxError {
return &SyntaxError{
msg: fmt.Sprintf("json: %s unexpected end of JSON input", msg),
Offset: cursor,
}
}
func errExpected(msg string, cursor int64) *SyntaxError {
return &SyntaxError{msg: fmt.Sprintf("expected %s", msg), Offset: cursor}
}
func errInvalidCharacter(c byte, context string, cursor int64) *SyntaxError {
if c == 0 {
return &SyntaxError{
msg: fmt.Sprintf("json: invalid character as %s", context),
Offset: cursor,
}
}
return &SyntaxError{
msg: fmt.Sprintf("json: invalid character %c as %s", c, context),
Offset: cursor,
}
}
var (
errExceededMaxDepth = errors.ErrExceededMaxDepth
errNotAtBeginningOfValue = errors.ErrNotAtBeginningOfValue
errUnexpectedEndOfJSON = errors.ErrUnexpectedEndOfJSON
errExpected = errors.ErrExpected
errInvalidCharacter = errors.ErrInvalidCharacter
errSyntax = errors.ErrSyntax
errMarshaler = errors.ErrMarshaler
)

View File

@ -1,18 +1,6 @@
package json
import "reflect"
func NewSyntaxError(msg string, offset int64) *SyntaxError {
return &SyntaxError{
msg: msg,
Offset: offset,
}
}
func NewMarshalerError(typ reflect.Type, err error, msg string) *MarshalerError {
return &MarshalerError{
Type: typ,
Err: err,
sourceFunc: msg,
}
}
var (
NewSyntaxError = errSyntax
NewMarshalerError = errMarshaler
)

157
internal/errors/error.go Normal file
View File

@ -0,0 +1,157 @@
package errors
import (
"fmt"
"reflect"
"strconv"
)
type InvalidUTF8Error struct {
S string // the whole string value that caused the error
}
func (e *InvalidUTF8Error) Error() string {
return fmt.Sprintf("json: invalid UTF-8 in string: %s", strconv.Quote(e.S))
}
type InvalidUnmarshalError struct {
Type reflect.Type
}
func (e *InvalidUnmarshalError) Error() string {
if e.Type == nil {
return "json: Unmarshal(nil)"
}
if e.Type.Kind() != reflect.Ptr {
return fmt.Sprintf("json: Unmarshal(non-pointer %s)", e.Type)
}
return fmt.Sprintf("json: Unmarshal(nil %s)", e.Type)
}
// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method.
type MarshalerError struct {
Type reflect.Type
Err error
sourceFunc string
}
func (e *MarshalerError) Error() string {
srcFunc := e.sourceFunc
if srcFunc == "" {
srcFunc = "MarshalJSON"
}
return fmt.Sprintf("json: error calling %s for type %s: %s", srcFunc, e.Type, e.Err.Error())
}
// Unwrap returns the underlying error.
func (e *MarshalerError) Unwrap() error { return e.Err }
// A SyntaxError is a description of a JSON syntax error.
type SyntaxError struct {
msg string // description of error
Offset int64 // error occurred after reading Offset bytes
}
func (e *SyntaxError) Error() string { return e.msg }
// An UnmarshalFieldError describes a JSON object key that
// led to an unexported (and therefore unwritable) struct field.
//
// Deprecated: No longer used; kept for compatibility.
type UnmarshalFieldError struct {
Key string
Type reflect.Type
Field reflect.StructField
}
func (e *UnmarshalFieldError) Error() string {
return fmt.Sprintf("json: cannot unmarshal object key %s into unexported field %s of type %s",
strconv.Quote(e.Key), e.Field.Name, e.Type.String(),
)
}
// An UnmarshalTypeError describes a JSON value that was
// not appropriate for a value of a specific Go type.
type UnmarshalTypeError struct {
Value string // description of JSON value - "bool", "array", "number -5"
Type reflect.Type // type of Go value it could not be assigned to
Offset int64 // error occurred after reading Offset bytes
Struct string // name of the struct type containing the field
Field string // the full path from root node to the field
}
func (e *UnmarshalTypeError) Error() string {
if e.Struct != "" || e.Field != "" {
return fmt.Sprintf("json: cannot unmarshal %s into Go struct field %s.%s of type %s",
e.Value, e.Struct, e.Field, e.Type,
)
}
return fmt.Sprintf("json: cannot unmarshal %s into Go value of type %s", e.Value, e.Type)
}
// An UnsupportedTypeError is returned by Marshal when attempting
// to encode an unsupported value type.
type UnsupportedTypeError struct {
Type reflect.Type
}
func (e *UnsupportedTypeError) Error() string {
return fmt.Sprintf("json: unsupported type: %s", e.Type)
}
type UnsupportedValueError struct {
Value reflect.Value
Str string
}
func (e *UnsupportedValueError) Error() string {
return fmt.Sprintf("json: unsupported value: %s", e.Str)
}
func ErrSyntax(msg string, offset int64) *SyntaxError {
return &SyntaxError{msg: msg, Offset: offset}
}
func ErrMarshaler(typ reflect.Type, err error, msg string) *MarshalerError {
return &MarshalerError{
Type: typ,
Err: err,
sourceFunc: msg,
}
}
func ErrExceededMaxDepth(c byte, cursor int64) *SyntaxError {
return &SyntaxError{
msg: fmt.Sprintf(`invalid character "%c" exceeded max depth`, c),
Offset: cursor,
}
}
func ErrNotAtBeginningOfValue(cursor int64) *SyntaxError {
return &SyntaxError{msg: "not at beginning of value", Offset: cursor}
}
func ErrUnexpectedEndOfJSON(msg string, cursor int64) *SyntaxError {
return &SyntaxError{
msg: fmt.Sprintf("json: %s unexpected end of JSON input", msg),
Offset: cursor,
}
}
func ErrExpected(msg string, cursor int64) *SyntaxError {
return &SyntaxError{msg: fmt.Sprintf("expected %s", msg), Offset: cursor}
}
func ErrInvalidCharacter(c byte, context string, cursor int64) *SyntaxError {
if c == 0 {
return &SyntaxError{
msg: fmt.Sprintf("json: invalid character as %s", context),
Offset: cursor,
}
}
return &SyntaxError{
msg: fmt.Sprintf("json: invalid character %c as %s", c, context),
Offset: cursor,
}
}