From 377d0b0dfccf7b15831a6874be3248111e6cb161 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Sat, 13 Mar 2021 13:31:14 +0900 Subject: [PATCH 01/15] Move error types to internal/errors package --- decode_float.go | 4 +- decode_number.go | 4 +- encode_vm.go | 2 +- encode_vm_escaped_indent.go | 63 ++++----------- encode_vm_indent.go | 63 ++++----------- error.go | 140 +++++--------------------------- export_test.go | 20 +---- internal/errors/error.go | 157 ++++++++++++++++++++++++++++++++++++ 8 files changed, 212 insertions(+), 241 deletions(-) create mode 100644 internal/errors/error.go diff --git a/decode_float.go b/decode_float.go index cda8ec5..6c2a390 100644 --- a/decode_float.go +++ b/decode_float.go @@ -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 diff --git a/decode_number.go b/decode_number.go index c667161..07022f8 100644 --- a/decode_number.go +++ b/decode_number.go @@ -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)) diff --git a/encode_vm.go b/encode_vm.go index 0488be3..950e5a3 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -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, diff --git a/encode_vm_escaped_indent.go b/encode_vm_escaped_indent.go index 64b15b6..7776930 100644 --- a/encode_vm_escaped_indent.go +++ b/encode_vm_escaped_indent.go @@ -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) diff --git a/encode_vm_indent.go b/encode_vm_indent.go index 39230e4..8d7653e 100644 --- a/encode_vm_indent.go +++ b/encode_vm_indent.go @@ -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) diff --git a/error.go b/error.go index 71fd94f..2487b07 100644 --- a/error.go +++ b/error.go @@ -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 +) diff --git a/export_test.go b/export_test.go index aa72fdb..b0e3532 100644 --- a/export_test.go +++ b/export_test.go @@ -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 +) diff --git a/internal/errors/error.go b/internal/errors/error.go new file mode 100644 index 0000000..329e2f1 --- /dev/null +++ b/internal/errors/error.go @@ -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, + } +} From 2385cfcdbf1ed105eda2b9cd02d85554b2e99c62 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Sat, 13 Mar 2021 14:12:31 +0900 Subject: [PATCH 02/15] Move rtype to internal/runtime package --- decode.go | 6 +- decode_interface.go | 8 +- decode_unmarshal_json.go | 4 +- decode_unmarshal_text.go | 4 +- encode.go | 6 +- encode_opcode_test.go | 2 +- encode_vm.go | 6 +- encode_vm_escaped.go | 2 +- encode_vm_escaped_indent.go | 2 +- encode_vm_indent.go | 2 +- internal/runtime/rtype.go | 262 +++++++++++++++++++++++++++++++++++ rtype.go | 267 +++--------------------------------- 12 files changed, 301 insertions(+), 270 deletions(-) create mode 100644 internal/runtime/rtype.go diff --git a/decode.go b/decode.go index e84570e..e5c4064 100644 --- a/decode.go +++ b/decode.go @@ -37,7 +37,7 @@ func unmarshal(data []byte, v interface{}) error { src := make([]byte, len(data)+1) // append nul byte to the end copy(src, data) - header := (*interfaceHeader)(unsafe.Pointer(&v)) + header := (*emptyInterface)(unsafe.Pointer(&v)) if err := validateType(header.typ, uintptr(header.ptr)); err != nil { return err @@ -56,7 +56,7 @@ func unmarshalNoEscape(data []byte, v interface{}) error { src := make([]byte, len(data)+1) // append nul byte to the end copy(src, data) - header := (*interfaceHeader)(unsafe.Pointer(&v)) + header := (*emptyInterface)(unsafe.Pointer(&v)) if err := validateType(header.typ, uintptr(header.ptr)); err != nil { return err @@ -129,7 +129,7 @@ func (d *Decoder) prepareForDecode() error { // See the documentation for Unmarshal for details about // the conversion of JSON into a Go value. func (d *Decoder) Decode(v interface{}) error { - header := (*interfaceHeader)(unsafe.Pointer(&v)) + header := (*emptyInterface)(unsafe.Pointer(&v)) typ := header.typ ptr := uintptr(header.ptr) typeptr := uintptr(unsafe.Pointer(typ)) diff --git a/decode_interface.go b/decode_interface.go index 20f5ad5..744b821 100644 --- a/decode_interface.go +++ b/decode_interface.go @@ -202,7 +202,7 @@ func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p } func (d *interfaceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { - runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: d.typ, ptr: p, })) @@ -217,7 +217,7 @@ func (d *interfaceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer return d.errUnmarshalType(rv.Type(), s.totalOffset()) } iface := rv.Interface() - ifaceHeader := (*interfaceHeader)(unsafe.Pointer(&iface)) + ifaceHeader := (*emptyInterface)(unsafe.Pointer(&iface)) typ := ifaceHeader.typ if ifaceHeader.ptr == nil || d.typ == typ || typ == nil { // concrete type is empty interface @@ -252,7 +252,7 @@ func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *Unm } func (d *interfaceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { - runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: d.typ, ptr: p, })) @@ -268,7 +268,7 @@ func (d *interfaceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Poin } iface := rv.Interface() - ifaceHeader := (*interfaceHeader)(unsafe.Pointer(&iface)) + ifaceHeader := (*emptyInterface)(unsafe.Pointer(&iface)) typ := ifaceHeader.typ if ifaceHeader.ptr == nil || d.typ == typ || typ == nil { // concrete type is empty interface diff --git a/decode_unmarshal_json.go b/decode_unmarshal_json.go index 1767c1f..faa593b 100644 --- a/decode_unmarshal_json.go +++ b/decode_unmarshal_json.go @@ -38,7 +38,7 @@ func (d *unmarshalJSONDecoder) decodeStream(s *stream, depth int64, p unsafe.Poi dst := make([]byte, len(src)) copy(dst, src) - v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: d.typ, ptr: p, })) @@ -60,7 +60,7 @@ func (d *unmarshalJSONDecoder) decode(buf []byte, cursor, depth int64, p unsafe. dst := make([]byte, len(src)) copy(dst, src) - v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: d.typ, ptr: p, })) diff --git a/decode_unmarshal_text.go b/decode_unmarshal_text.go index 7b560af..cd30e16 100644 --- a/decode_unmarshal_text.go +++ b/decode_unmarshal_text.go @@ -77,7 +77,7 @@ func (d *unmarshalTextDecoder) decodeStream(s *stream, depth int64, p unsafe.Poi if b, ok := unquoteBytes(dst); ok { dst = b } - v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: d.typ, ptr: p, })) @@ -127,7 +127,7 @@ func (d *unmarshalTextDecoder) decode(buf []byte, cursor, depth int64, p unsafe. if s, ok := unquoteBytes(src); ok { src = s } - v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: d.typ, ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), })) diff --git a/encode.go b/encode.go index 2d51c57..cb52b07 100644 --- a/encode.go +++ b/encode.go @@ -195,7 +195,7 @@ func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, b = encodeComma(b) return b, nil } - header := (*interfaceHeader)(unsafe.Pointer(&v)) + header := (*emptyInterface)(unsafe.Pointer(&v)) typ := header.typ typeptr := uintptr(unsafe.Pointer(typ)) @@ -225,7 +225,7 @@ func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) b = encodeComma(b) return b, nil } - header := (*interfaceHeader)(unsafe.Pointer(&v)) + header := (*emptyInterface)(unsafe.Pointer(&v)) typ := header.typ typeptr := uintptr(unsafe.Pointer(typ)) @@ -252,7 +252,7 @@ func encodeIndent(ctx *encodeRuntimeContext, v interface{}, prefix, indent strin b = encodeIndentComma(b) return b, nil } - header := (*interfaceHeader)(unsafe.Pointer(&v)) + header := (*emptyInterface)(unsafe.Pointer(&v)) typ := header.typ typeptr := uintptr(unsafe.Pointer(typ)) diff --git a/encode_opcode_test.go b/encode_opcode_test.go index 919a688..96d3a3d 100644 --- a/encode_opcode_test.go +++ b/encode_opcode_test.go @@ -7,7 +7,7 @@ import ( func TestDumpOpcode(t *testing.T) { var v interface{} = 1 - header := (*interfaceHeader)(unsafe.Pointer(&v)) + header := (*emptyInterface)(unsafe.Pointer(&v)) typ := header.typ typeptr := uintptr(unsafe.Pointer(typ)) codeSet, err := encodeCompileToGetCodeSet(typeptr) diff --git a/encode_vm.go b/encode_vm.go index 950e5a3..510f105 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -37,14 +37,14 @@ func ptrToUnsafePtr(p uintptr) unsafe.Pointer { return *(*unsafe.Pointer)(unsafe.Pointer(&p)) } func ptrToInterface(code *opcode, p uintptr) interface{} { - return *(*interface{})(unsafe.Pointer(&interfaceHeader{ + return *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: code.typ, ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), })) } func errUnsupportedValue(code *opcode, ptr uintptr) *UnsupportedValueError { - v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: code.typ, ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)), })) @@ -163,7 +163,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco } } ctx.seenPtr = append(ctx.seenPtr, ptr) - iface := (*interfaceHeader)(ptrToUnsafePtr(ptr)) + iface := (*emptyInterface)(ptrToUnsafePtr(ptr)) if iface == nil || iface.ptr == nil { b = encodeNull(b) b = encodeComma(b) diff --git a/encode_vm_escaped.go b/encode_vm_escaped.go index 82c1953..81dfc77 100644 --- a/encode_vm_escaped.go +++ b/encode_vm_escaped.go @@ -104,7 +104,7 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o } } ctx.seenPtr = append(ctx.seenPtr, ptr) - iface := (*interfaceHeader)(ptrToUnsafePtr(ptr)) + iface := (*emptyInterface)(ptrToUnsafePtr(ptr)) if iface == nil || iface.ptr == nil { b = encodeNull(b) b = encodeComma(b) diff --git a/encode_vm_escaped_indent.go b/encode_vm_escaped_indent.go index 7776930..3e31da6 100644 --- a/encode_vm_escaped_indent.go +++ b/encode_vm_escaped_indent.go @@ -95,7 +95,7 @@ func encodeRunEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode } } ctx.seenPtr = append(ctx.seenPtr, ptr) - iface := (*interfaceHeader)(ptrToUnsafePtr(ptr)) + iface := (*emptyInterface)(ptrToUnsafePtr(ptr)) if iface == nil || iface.ptr == nil { b = encodeNull(b) b = encodeIndentComma(b) diff --git a/encode_vm_indent.go b/encode_vm_indent.go index 8d7653e..3612dc8 100644 --- a/encode_vm_indent.go +++ b/encode_vm_indent.go @@ -95,7 +95,7 @@ func encodeRunIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, op } } ctx.seenPtr = append(ctx.seenPtr, ptr) - iface := (*interfaceHeader)(ptrToUnsafePtr(ptr)) + iface := (*emptyInterface)(ptrToUnsafePtr(ptr)) if iface == nil || iface.ptr == nil { b = encodeNull(b) b = encodeIndentComma(b) diff --git a/internal/runtime/rtype.go b/internal/runtime/rtype.go new file mode 100644 index 0000000..c73223d --- /dev/null +++ b/internal/runtime/rtype.go @@ -0,0 +1,262 @@ +package runtime + +import ( + "reflect" + "unsafe" +) + +// Type representing reflect.rtype for noescape trick +type Type struct{} + +//go:linkname rtype_Align reflect.(*rtype).Align +//go:noescape +func rtype_Align(*Type) int + +func (t *Type) Align() int { + return rtype_Align(t) +} + +//go:linkname rtype_FieldAlign reflect.(*rtype).FieldAlign +//go:noescape +func rtype_FieldAlign(*Type) int + +func (t *Type) FieldAlign() int { + return rtype_FieldAlign(t) +} + +//go:linkname rtype_Method reflect.(*rtype).Method +//go:noescape +func rtype_Method(*Type, int) reflect.Method + +func (t *Type) Method(a0 int) reflect.Method { + return rtype_Method(t, a0) +} + +//go:linkname rtype_MethodByName reflect.(*rtype).MethodByName +//go:noescape +func rtype_MethodByName(*Type, string) (reflect.Method, bool) + +func (t *Type) MethodByName(a0 string) (reflect.Method, bool) { + return rtype_MethodByName(t, a0) +} + +//go:linkname rtype_NumMethod reflect.(*rtype).NumMethod +//go:noescape +func rtype_NumMethod(*Type) int + +func (t *Type) NumMethod() int { + return rtype_NumMethod(t) +} + +//go:linkname rtype_Name reflect.(*rtype).Name +//go:noescape +func rtype_Name(*Type) string + +func (t *Type) Name() string { + return rtype_Name(t) +} + +//go:linkname rtype_PkgPath reflect.(*rtype).PkgPath +//go:noescape +func rtype_PkgPath(*Type) string + +func (t *Type) PkgPath() string { + return rtype_PkgPath(t) +} + +//go:linkname rtype_Size reflect.(*rtype).Size +//go:noescape +func rtype_Size(*Type) uintptr + +func (t *Type) Size() uintptr { + return rtype_Size(t) +} + +//go:linkname rtype_String reflect.(*rtype).String +//go:noescape +func rtype_String(*Type) string + +func (t *Type) String() string { + return rtype_String(t) +} + +//go:linkname rtype_Kind reflect.(*rtype).Kind +//go:noescape +func rtype_Kind(*Type) reflect.Kind + +func (t *Type) Kind() reflect.Kind { + return rtype_Kind(t) +} + +//go:linkname rtype_Implements reflect.(*rtype).Implements +//go:noescape +func rtype_Implements(*Type, reflect.Type) bool + +func (t *Type) Implements(u reflect.Type) bool { + return rtype_Implements(t, u) +} + +//go:linkname rtype_AssignableTo reflect.(*rtype).AssignableTo +//go:noescape +func rtype_AssignableTo(*Type, reflect.Type) bool + +func (t *Type) AssignableTo(u reflect.Type) bool { + return rtype_AssignableTo(t, u) +} + +//go:linkname rtype_ConvertibleTo reflect.(*rtype).ConvertibleTo +//go:noescape +func rtype_ConvertibleTo(*Type, reflect.Type) bool + +func (t *Type) ConvertibleTo(u reflect.Type) bool { + return rtype_ConvertibleTo(t, u) +} + +//go:linkname rtype_Comparable reflect.(*rtype).Comparable +//go:noescape +func rtype_Comparable(*Type) bool + +func (t *Type) Comparable() bool { + return rtype_Comparable(t) +} + +//go:linkname rtype_Bits reflect.(*rtype).Bits +//go:noescape +func rtype_Bits(*Type) int + +func (t *Type) Bits() int { + return rtype_Bits(t) +} + +//go:linkname rtype_ChanDir reflect.(*rtype).ChanDir +//go:noescape +func rtype_ChanDir(*Type) reflect.ChanDir + +func (t *Type) ChanDir() reflect.ChanDir { + return rtype_ChanDir(t) +} + +//go:linkname rtype_IsVariadic reflect.(*rtype).IsVariadic +//go:noescape +func rtype_IsVariadic(*Type) bool + +func (t *Type) IsVariadic() bool { + return rtype_IsVariadic(t) +} + +//go:linkname rtype_Elem reflect.(*rtype).Elem +//go:noescape +func rtype_Elem(*Type) reflect.Type + +func (t *Type) Elem() *Type { + return Type2RType(rtype_Elem(t)) +} + +//go:linkname rtype_Field reflect.(*rtype).Field +//go:noescape +func rtype_Field(*Type, int) reflect.StructField + +func (t *Type) Field(i int) reflect.StructField { + return rtype_Field(t, i) +} + +//go:linkname rtype_FieldByIndex reflect.(*rtype).FieldByIndex +//go:noescape +func rtype_FieldByIndex(*Type, []int) reflect.StructField + +func (t *Type) FieldByIndex(index []int) reflect.StructField { + return rtype_FieldByIndex(t, index) +} + +//go:linkname rtype_FieldByName reflect.(*rtype).FieldByName +//go:noescape +func rtype_FieldByName(*Type, string) (reflect.StructField, bool) + +func (t *Type) FieldByName(name string) (reflect.StructField, bool) { + return rtype_FieldByName(t, name) +} + +//go:linkname rtype_FieldByNameFunc reflect.(*rtype).FieldByNameFunc +//go:noescape +func rtype_FieldByNameFunc(*Type, func(string) bool) (reflect.StructField, bool) + +func (t *Type) FieldByNameFunc(match func(string) bool) (reflect.StructField, bool) { + return rtype_FieldByNameFunc(t, match) +} + +//go:linkname rtype_In reflect.(*rtype).In +//go:noescape +func rtype_In(*Type, int) reflect.Type + +func (t *Type) In(i int) reflect.Type { + return rtype_In(t, i) +} + +//go:linkname rtype_Key reflect.(*rtype).Key +//go:noescape +func rtype_Key(*Type) reflect.Type + +func (t *Type) Key() *Type { + return Type2RType(rtype_Key(t)) +} + +//go:linkname rtype_Len reflect.(*rtype).Len +//go:noescape +func rtype_Len(*Type) int + +func (t *Type) Len() int { + return rtype_Len(t) +} + +//go:linkname rtype_NumField reflect.(*rtype).NumField +//go:noescape +func rtype_NumField(*Type) int + +func (t *Type) NumField() int { + return rtype_NumField(t) +} + +//go:linkname rtype_NumIn reflect.(*rtype).NumIn +//go:noescape +func rtype_NumIn(*Type) int + +func (t *Type) NumIn() int { + return rtype_NumIn(t) +} + +//go:linkname rtype_NumOut reflect.(*rtype).NumOut +//go:noescape +func rtype_NumOut(*Type) int + +func (t *Type) NumOut() int { + return rtype_NumOut(t) +} + +//go:linkname rtype_Out reflect.(*rtype).Out +//go:noescape +func rtype_Out(*Type, int) reflect.Type + +//go:linkname PtrTo reflect.(*rtype).ptrTo +//go:noescape +func PtrTo(*Type) *Type + +func (t *Type) Out(i int) reflect.Type { + return rtype_Out(t, i) +} + +//go:linkname IfaceIndir reflect.ifaceIndir +//go:noescape +func IfaceIndir(*Type) bool + +//go:linkname RType2Type reflect.toType +//go:noescape +func RType2Type(t *Type) reflect.Type + +type emptyInterface struct { + typ *Type + ptr unsafe.Pointer +} + +func Type2RType(t reflect.Type) *Type { + return (*Type)(((*emptyInterface)(unsafe.Pointer(&t))).ptr) +} diff --git a/rtype.go b/rtype.go index e505528..6d06865 100644 --- a/rtype.go +++ b/rtype.go @@ -3,260 +3,29 @@ package json import ( "reflect" "unsafe" + + "github.com/goccy/go-json/internal/runtime" ) -// rtype representing reflect.rtype for noescape trick -type rtype struct{} +type rtype = runtime.Type -//go:linkname rtype_Align reflect.(*rtype).Align -//go:noescape -func rtype_Align(*rtype) int - -func (t *rtype) Align() int { - return rtype_Align(t) -} - -//go:linkname rtype_FieldAlign reflect.(*rtype).FieldAlign -//go:noescape -func rtype_FieldAlign(*rtype) int - -func (t *rtype) FieldAlign() int { - return rtype_FieldAlign(t) -} - -//go:linkname rtype_Method reflect.(*rtype).Method -//go:noescape -func rtype_Method(*rtype, int) reflect.Method - -func (t *rtype) Method(a0 int) reflect.Method { - return rtype_Method(t, a0) -} - -//go:linkname rtype_MethodByName reflect.(*rtype).MethodByName -//go:noescape -func rtype_MethodByName(*rtype, string) (reflect.Method, bool) - -func (t *rtype) MethodByName(a0 string) (reflect.Method, bool) { - return rtype_MethodByName(t, a0) -} - -//go:linkname rtype_NumMethod reflect.(*rtype).NumMethod -//go:noescape -func rtype_NumMethod(*rtype) int - -func (t *rtype) NumMethod() int { - return rtype_NumMethod(t) -} - -//go:linkname rtype_Name reflect.(*rtype).Name -//go:noescape -func rtype_Name(*rtype) string - -func (t *rtype) Name() string { - return rtype_Name(t) -} - -//go:linkname rtype_PkgPath reflect.(*rtype).PkgPath -//go:noescape -func rtype_PkgPath(*rtype) string - -func (t *rtype) PkgPath() string { - return rtype_PkgPath(t) -} - -//go:linkname rtype_Size reflect.(*rtype).Size -//go:noescape -func rtype_Size(*rtype) uintptr - -func (t *rtype) Size() uintptr { - return rtype_Size(t) -} - -//go:linkname rtype_String reflect.(*rtype).String -//go:noescape -func rtype_String(*rtype) string - -func (t *rtype) String() string { - return rtype_String(t) -} - -//go:linkname rtype_Kind reflect.(*rtype).Kind -//go:noescape -func rtype_Kind(*rtype) reflect.Kind - -func (t *rtype) Kind() reflect.Kind { - return rtype_Kind(t) -} - -//go:linkname rtype_Implements reflect.(*rtype).Implements -//go:noescape -func rtype_Implements(*rtype, reflect.Type) bool - -func (t *rtype) Implements(u reflect.Type) bool { - return rtype_Implements(t, u) -} - -//go:linkname rtype_AssignableTo reflect.(*rtype).AssignableTo -//go:noescape -func rtype_AssignableTo(*rtype, reflect.Type) bool - -func (t *rtype) AssignableTo(u reflect.Type) bool { - return rtype_AssignableTo(t, u) -} - -//go:linkname rtype_ConvertibleTo reflect.(*rtype).ConvertibleTo -//go:noescape -func rtype_ConvertibleTo(*rtype, reflect.Type) bool - -func (t *rtype) ConvertibleTo(u reflect.Type) bool { - return rtype_ConvertibleTo(t, u) -} - -//go:linkname rtype_Comparable reflect.(*rtype).Comparable -//go:noescape -func rtype_Comparable(*rtype) bool - -func (t *rtype) Comparable() bool { - return rtype_Comparable(t) -} - -//go:linkname rtype_Bits reflect.(*rtype).Bits -//go:noescape -func rtype_Bits(*rtype) int - -func (t *rtype) Bits() int { - return rtype_Bits(t) -} - -//go:linkname rtype_ChanDir reflect.(*rtype).ChanDir -//go:noescape -func rtype_ChanDir(*rtype) reflect.ChanDir - -func (t *rtype) ChanDir() reflect.ChanDir { - return rtype_ChanDir(t) -} - -//go:linkname rtype_IsVariadic reflect.(*rtype).IsVariadic -//go:noescape -func rtype_IsVariadic(*rtype) bool - -func (t *rtype) IsVariadic() bool { - return rtype_IsVariadic(t) -} - -//go:linkname rtype_Elem reflect.(*rtype).Elem -//go:noescape -func rtype_Elem(*rtype) reflect.Type - -func (t *rtype) Elem() *rtype { - return type2rtype(rtype_Elem(t)) -} - -//go:linkname rtype_Field reflect.(*rtype).Field -//go:noescape -func rtype_Field(*rtype, int) reflect.StructField - -func (t *rtype) Field(i int) reflect.StructField { - return rtype_Field(t, i) -} - -//go:linkname rtype_FieldByIndex reflect.(*rtype).FieldByIndex -//go:noescape -func rtype_FieldByIndex(*rtype, []int) reflect.StructField - -func (t *rtype) FieldByIndex(index []int) reflect.StructField { - return rtype_FieldByIndex(t, index) -} - -//go:linkname rtype_FieldByName reflect.(*rtype).FieldByName -//go:noescape -func rtype_FieldByName(*rtype, string) (reflect.StructField, bool) - -func (t *rtype) FieldByName(name string) (reflect.StructField, bool) { - return rtype_FieldByName(t, name) -} - -//go:linkname rtype_FieldByNameFunc reflect.(*rtype).FieldByNameFunc -//go:noescape -func rtype_FieldByNameFunc(*rtype, func(string) bool) (reflect.StructField, bool) - -func (t *rtype) FieldByNameFunc(match func(string) bool) (reflect.StructField, bool) { - return rtype_FieldByNameFunc(t, match) -} - -//go:linkname rtype_In reflect.(*rtype).In -//go:noescape -func rtype_In(*rtype, int) reflect.Type - -func (t *rtype) In(i int) reflect.Type { - return rtype_In(t, i) -} - -//go:linkname rtype_Key reflect.(*rtype).Key -//go:noescape -func rtype_Key(*rtype) reflect.Type - -func (t *rtype) Key() *rtype { - return type2rtype(rtype_Key(t)) -} - -//go:linkname rtype_Len reflect.(*rtype).Len -//go:noescape -func rtype_Len(*rtype) int - -func (t *rtype) Len() int { - return rtype_Len(t) -} - -//go:linkname rtype_NumField reflect.(*rtype).NumField -//go:noescape -func rtype_NumField(*rtype) int - -func (t *rtype) NumField() int { - return rtype_NumField(t) -} - -//go:linkname rtype_NumIn reflect.(*rtype).NumIn -//go:noescape -func rtype_NumIn(*rtype) int - -func (t *rtype) NumIn() int { - return rtype_NumIn(t) -} - -//go:linkname rtype_NumOut reflect.(*rtype).NumOut -//go:noescape -func rtype_NumOut(*rtype) int - -func (t *rtype) NumOut() int { - return rtype_NumOut(t) -} - -//go:linkname rtype_Out reflect.(*rtype).Out -//go:noescape -func rtype_Out(*rtype, int) reflect.Type - -//go:linkname rtype_ptrTo reflect.(*rtype).ptrTo -//go:noescape -func rtype_ptrTo(*rtype) *rtype - -func (t *rtype) Out(i int) reflect.Type { - return rtype_Out(t, i) -} - -//go:linkname ifaceIndir reflect.ifaceIndir -//go:noescape -func ifaceIndir(*rtype) bool - -//go:linkname rtype2type reflect.toType -//go:noescape -func rtype2type(t *rtype) reflect.Type - -type interfaceHeader struct { +type emptyInterface struct { typ *rtype ptr unsafe.Pointer } -func type2rtype(t reflect.Type) *rtype { - return (*rtype)(((*interfaceHeader)(unsafe.Pointer(&t))).ptr) +func rtype_ptrTo(t *rtype) *rtype { + return runtime.PtrTo(t) +} + +func ifaceIndir(t *rtype) bool { + return runtime.IfaceIndir(t) +} + +func rtype2type(t *rtype) reflect.Type { + return runtime.RType2Type(t) +} + +func type2rtype(t reflect.Type) *rtype { + return runtime.Type2RType(t) } From c45f1e8b2c8f9a4481ee3cbd1318fba72babdd21 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 16 Mar 2021 02:50:19 +0900 Subject: [PATCH 03/15] Add internal/vm package --- Makefile | 4 + encode.go | 2 + {cmd => internal/cmd}/generator/main.go | 136 +- internal/encoder/compiler/compiler.go | 1 + internal/encoder/compiler/norace.go | 11 + internal/encoder/encoder.go | 407 +++ internal/encoder/int.go | 124 + internal/encoder/map112.go | 8 + internal/encoder/map113.go | 8 + internal/encoder/optype.go | 1025 ++++++ internal/encoder/string.go | 637 ++++ internal/encoder/vm/vm.go | 3759 +++++++++++++++++++++++ internal/runtime/type.go | 9 + 13 files changed, 6060 insertions(+), 71 deletions(-) rename {cmd => internal/cmd}/generator/main.go (74%) create mode 100644 internal/encoder/compiler/compiler.go create mode 100644 internal/encoder/compiler/norace.go create mode 100644 internal/encoder/encoder.go create mode 100644 internal/encoder/int.go create mode 100644 internal/encoder/map112.go create mode 100644 internal/encoder/map113.go create mode 100644 internal/encoder/optype.go create mode 100644 internal/encoder/string.go create mode 100644 internal/encoder/vm/vm.go create mode 100644 internal/runtime/type.go diff --git a/Makefile b/Makefile index 9f68367..75327d4 100644 --- a/Makefile +++ b/Makefile @@ -26,3 +26,7 @@ golangci-lint: | $(BIN_DIR) GOBIN=$(BIN_DIR) go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.36.0; \ rm -rf $$GOLANGCI_LINT_TMP_DIR; \ } + +.PHONY: generate +generate: + go generate ./internal/... diff --git a/encode.go b/encode.go index cb52b07..7f22b25 100644 --- a/encode.go +++ b/encode.go @@ -12,6 +12,8 @@ import ( "strings" "sync" "unsafe" + + _ "github.com/goccy/go-json/internal/encoder/vm" ) // An Encoder writes JSON values to an output stream. diff --git a/cmd/generator/main.go b/internal/cmd/generator/main.go similarity index 74% rename from cmd/generator/main.go rename to internal/cmd/generator/main.go index 1ef7948..85fdadc 100644 --- a/cmd/generator/main.go +++ b/internal/cmd/generator/main.go @@ -66,18 +66,18 @@ func createOpType(op, code string) opType { } func _main() error { - tmpl, err := template.New("").Parse(`// Code generated by cmd/generator. DO NOT EDIT! -package json + tmpl, err := template.New("").Parse(`// Code generated by internal/cmd/generator. DO NOT EDIT! +package encoder import ( "strings" ) -type codeType int +type CodeType int const ( {{- range $index, $type := .CodeTypes }} - code{{ $type }} codeType = {{ $index }} + Code{{ $type }} CodeType = {{ $index }} {{- end }} ) @@ -87,92 +87,86 @@ var opTypeStrings = [{{ .OpLen }}]string{ {{- end }} } -type opType int +type OpType int const ( {{- range $index, $type := .OpTypes }} - op{{ $type.Op }} opType = {{ $index }} + Op{{ $type.Op }} OpType = {{ $index }} {{- end }} ) -func (t opType) String() string { +func (t OpType) String() string { if int(t) >= {{ .OpLen }} { return "" } return opTypeStrings[int(t)] } -func (t opType) codeType() codeType { +func (t OpType) CodeType() CodeType { if strings.Contains(t.String(), "Struct") { if strings.Contains(t.String(), "End") { - return codeStructEnd + return CodeStructEnd } - return codeStructField + return CodeStructField } - if t.String() == "Array" || t.String() == "ArrayPtr" { - return codeArrayHead - } - if strings.Contains(t.String(), "ArrayElem") { - return codeArrayElem - } - if t.String() == "Slice" || t.String() == "SlicePtr" { - return codeSliceHead - } - if strings.Contains(t.String(), "SliceElem") { - return codeSliceElem - } - if t.String() == "Map" || t.String() == "MapPtr" { - return codeMapHead - } - if strings.Contains(t.String(), "MapKey") { - return codeMapKey - } - if strings.Contains(t.String(), "MapValue") { - return codeMapValue - } - if strings.Contains(t.String(), "MapEnd") { - return codeMapEnd + switch t { + case OpArray, OpArrayPtr: + return CodeArrayHead + case OpArrayElem: + return CodeArrayElem + case OpSlice, OpSlicePtr: + return CodeSliceHead + case OpSliceElem: + return CodeSliceElem + case OpMap, OpMapPtr: + return CodeMapHead + case OpMapKey: + return CodeMapKey + case OpMapValue: + return CodeMapValue + case OpMapEnd: + return CodeMapEnd } - return codeOp + return CodeOp } -func (t opType) headToPtrHead() opType { +func (t OpType) HeadToPtrHead() OpType { if strings.Index(t.String(), "PtrHead") > 0 { return t } - idx := strings.Index(t.String(), "Field") + idx := strings.Index(t.String(), "Head") if idx == -1 { return t } - suffix := "Ptr"+t.String()[idx+len("Field"):] + suffix := "Ptr"+t.String()[idx+len("Head"):] const toPtrOffset = 3 - if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) { - return opType(int(t) + toPtrOffset) + if strings.Contains(OpType(int(t) + toPtrOffset).String(), suffix) { + return OpType(int(t) + toPtrOffset) } return t } -func (t opType) headToOmitEmptyHead() opType { +func (t OpType) HeadToOmitEmptyHead() OpType { const toOmitEmptyOffset = 1 - if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { - return opType(int(t) + toOmitEmptyOffset) + if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) } return t } -func (t opType) headToStringTagHead() opType { +func (t OpType) HeadToStringTagHead() OpType { const toStringTagOffset = 2 - if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") { - return opType(int(t) + toStringTagOffset) + if strings.Contains(OpType(int(t) + toStringTagOffset).String(), "StringTag") { + return OpType(int(t) + toStringTagOffset) } return t } -func (t opType) ptrHeadToHead() opType { +func (t OpType) PtrHeadToHead() OpType { idx := strings.Index(t.String(), "Ptr") if idx == -1 { return t @@ -180,36 +174,37 @@ func (t opType) ptrHeadToHead() opType { suffix := t.String()[idx+len("Ptr"):] const toPtrOffset = 3 - if strings.Contains(opType(int(t) - toPtrOffset).String(), suffix) { - return opType(int(t) - toPtrOffset) + if strings.Contains(OpType(int(t) - toPtrOffset).String(), suffix) { + return OpType(int(t) - toPtrOffset) } return t } -func (t opType) fieldToEnd() opType { - switch t { -{{- range $type := .OpTypes }} -{{- if $type.IsFieldToEnd }} - case op{{ $type.Op }}: - return op{{ call $type.FieldToEnd }} -{{- end }} -{{- end }} +func (t OpType) FieldToEnd() OpType { + idx := strings.Index(t.String(), "Field") + if idx == -1 { + return t + } + suffix := t.String()[idx+len("Field"):] + const toEndOffset = 3 + if strings.Contains(OpType(int(t) + toEndOffset).String(), "End"+suffix) { + return OpType(int(t) + toEndOffset) } return t } -func (t opType) fieldToOmitEmptyField() opType { +func (t OpType) FieldToOmitEmptyField() OpType { const toOmitEmptyOffset = 1 - if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { - return opType(int(t) + toOmitEmptyOffset) + if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) } return t } -func (t opType) fieldToStringTagField() opType { +func (t OpType) FieldToStringTagField() OpType { const toStringTagOffset = 2 - if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") { - return opType(int(t) + toStringTagOffset) + if strings.Contains(OpType(int(t) + toStringTagOffset).String(), "StringTag") { + return OpType(int(t) + toStringTagOffset) } return t } @@ -269,7 +264,7 @@ func (t opType) fieldToStringTagField() opType { typ := typ op := fmt.Sprintf( - "StructField%sHead%s%s", + "Struct%sHead%s%s", ptrOrNot, opt, typ, @@ -279,28 +274,28 @@ func (t opType) fieldToStringTagField() opType { Code: "StructField", HeadToPtrHead: func() string { return fmt.Sprintf( - "StructFieldPtrHead%s%s", + "StructPtrHead%s%s", opt, typ, ) }, HeadToOmitEmptyHead: func() string { return fmt.Sprintf( - "StructField%sHeadOmitEmpty%s", + "Struct%sHeadOmitEmpty%s", ptrOrNot, typ, ) }, HeadToStringTagHead: func() string { return fmt.Sprintf( - "StructField%sHeadStringTag%s", + "Struct%sHeadStringTag%s", ptrOrNot, typ, ) }, PtrHeadToHead: func() string { return fmt.Sprintf( - "StructFieldHead%s%s", + "StructHead%s%s", opt, typ, ) @@ -354,8 +349,6 @@ func (t opType) fieldToStringTagField() opType { }, }) } - } - for _, typ := range append(primitiveTypesUpper, "") { for _, opt := range []string{"", "OmitEmpty", "StringTag"} { opt := opt typ := typ @@ -390,7 +383,7 @@ func (t opType) fieldToStringTagField() opType { }); err != nil { return err } - path := filepath.Join(repoRoot(), "encode_optype.go") + path := filepath.Join(repoRoot(), "internal", "encoder", "optype.go") buf, err := format.Source(b.Bytes()) if err != nil { return err @@ -400,10 +393,11 @@ func (t opType) fieldToStringTagField() opType { func repoRoot() string { _, file, _, _ := runtime.Caller(0) - relativePathFromRepoRoot := filepath.Join("cmd", "generator") + relativePathFromRepoRoot := filepath.Join("internal", "cmd", "generator") return strings.TrimSuffix(filepath.Dir(file), relativePathFromRepoRoot) } +//go:generate go run main.go func main() { if err := _main(); err != nil { panic(err) diff --git a/internal/encoder/compiler/compiler.go b/internal/encoder/compiler/compiler.go new file mode 100644 index 0000000..a20d4fe --- /dev/null +++ b/internal/encoder/compiler/compiler.go @@ -0,0 +1 @@ +package compiler diff --git a/internal/encoder/compiler/norace.go b/internal/encoder/compiler/norace.go new file mode 100644 index 0000000..8299204 --- /dev/null +++ b/internal/encoder/compiler/norace.go @@ -0,0 +1,11 @@ +// +build !race + +package compiler + +import ( + "github.com/goccy/go-json/internal/encoder" +) + +func CompileToGetCodeSet(typeptr uintptr) (*encoder.OpcodeSet, error) { + return nil, nil +} diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go new file mode 100644 index 0000000..26725fc --- /dev/null +++ b/internal/encoder/encoder.go @@ -0,0 +1,407 @@ +package encoder + +import ( + "bytes" + "encoding" + "encoding/base64" + "encoding/json" + "fmt" + "math" + "reflect" + "strconv" + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type Option int + +const ( + HTMLEscapeOption Option = 1 << iota + IndentOption + UnorderedMapOption +) + +type Opcode struct { + Op OpType // operation type + Type *runtime.Type // go type + DisplayIdx int // opcode index + Key []byte // struct field key + EscapedKey []byte // struct field key ( HTML escaped ) + PtrNum int // pointer number: e.g. double pointer is 2. + DisplayKey string // key text to display + IsTaggedKey bool // whether tagged key + AnonymousKey bool // whether anonymous key + AnonymousHead bool // whether anonymous head or not + Indirect bool // whether indirect or not + Nilcheck bool // whether needs to nilcheck or not + AddrForMarshaler bool // whether needs to addr for marshaler or not + RshiftNum uint8 // use to take bit for judging whether negative integer or not + Mask uint64 // mask for number + Indent int // indent number + + Idx uintptr // offset to access ptr + HeadIdx uintptr // offset to access slice/struct head + ElemIdx uintptr // offset to access array/slice/map elem + Length uintptr // offset to access slice/map length or array length + MapIter uintptr // offset to access map iterator + MapPos uintptr // offset to access position list for sorted map + Offset uintptr // offset size from struct header + Size uintptr // array/slice elem size + + MapKey *Opcode // map key + MapValue *Opcode // map value + Elem *Opcode // array/slice elem + End *Opcode // array/slice/struct/map end + PrevField *Opcode // prev struct field + NextField *Opcode // next struct field + Next *Opcode // next opcode + Jmp *CompiledCode // for recursive call +} + +type OpcodeSet struct { + Code *Opcode + CodeLength int +} + +type CompiledCode struct { + Code *Opcode + Linked bool // whether recursive code already have linked + CurLen uintptr + NextLen uintptr +} + +const StartDetectingCyclesAfter = 1000 + +func Load(base uintptr, idx uintptr) uintptr { + addr := base + idx + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func Store(base uintptr, idx uintptr, p uintptr) { + addr := base + idx + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func LoadAndStoreNPtr(base uintptr, idx uintptr, ptrNum int) { + addr := base + idx + p := **(**uintptr)(unsafe.Pointer(&addr)) + for i := 0; i < ptrNum; i++ { + if p == 0 { + **(**uintptr)(unsafe.Pointer(&addr)) = 0 + return + } + p = PtrToPtr(p) + } + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func PtrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func PtrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func PtrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func PtrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func PtrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func PtrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func PtrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func PtrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func PtrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func PtrToNPtr(p uintptr, ptrNum int) uintptr { + for i := 0; i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = PtrToPtr(p) + } + return p +} + +func PtrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func PtrToInterface(code *Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func ErrUnsupportedValue(code *Opcode, ptr uintptr) *errors.UnsupportedValueError { + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)), + })) + return &errors.UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: fmt.Sprintf("encountered a cycle via %s", code.Type), + } +} + +func ErrUnsupportedFloat(v float64) *errors.UnsupportedValueError { + return &errors.UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: strconv.FormatFloat(v, 'g', -1, 64), + } +} + +func ErrMarshalerWithCode(code *Opcode, err error) *errors.MarshalerError { + return &errors.MarshalerError{ + Type: runtime.RType2Type(code.Type), + Err: err, + } +} + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +type MapItem struct { + Key []byte + Value []byte +} + +type Mapslice struct { + Items []MapItem +} + +func (m *Mapslice) Len() int { + return len(m.Items) +} + +func (m *Mapslice) Less(i, j int) bool { + return bytes.Compare(m.Items[i].Key, m.Items[j].Key) < 0 +} + +func (m *Mapslice) Swap(i, j int) { + m.Items[i], m.Items[j] = m.Items[j], m.Items[i] +} + +type MapContext struct { + Pos []int + Slice *Mapslice + Buf []byte +} + +var mapContextPool = sync.Pool{ + New: func() interface{} { + return &MapContext{} + }, +} + +func NewMapContext(mapLen int) *MapContext { + ctx := mapContextPool.Get().(*MapContext) + if ctx.Slice == nil { + ctx.Slice = &Mapslice{ + Items: make([]MapItem, 0, mapLen), + } + } + if cap(ctx.Pos) < (mapLen*2 + 1) { + ctx.Pos = make([]int, 0, mapLen*2+1) + ctx.Slice.Items = make([]MapItem, 0, mapLen) + } else { + ctx.Pos = ctx.Pos[:0] + ctx.Slice.Items = ctx.Slice.Items[:0] + } + ctx.Buf = ctx.Buf[:0] + return ctx +} + +func ReleaseMapContext(c *MapContext) { + mapContextPool.Put(c) +} + +//go:linkname MapIterInit reflect.mapiterinit +//go:noescape +func MapIterInit(mapType *runtime.Type, m unsafe.Pointer) unsafe.Pointer + +//go:linkname MapIterKey reflect.mapiterkey +//go:noescape +func MapIterKey(it unsafe.Pointer) unsafe.Pointer + +//go:linkname MapIterNext reflect.mapiternext +//go:noescape +func MapIterNext(it unsafe.Pointer) + +//go:linkname MapLen reflect.maplen +//go:noescape +func MapLen(m unsafe.Pointer) int + +type RuntimeContext struct { + Buf []byte + Ptrs []uintptr + KeepRefs []unsafe.Pointer + SeenPtr []uintptr + BaseIndent int + Prefix []byte + IndentStr []byte +} + +func (c *RuntimeContext) Init(p uintptr, codelen int) { + if len(c.Ptrs) < codelen { + c.Ptrs = make([]uintptr, codelen) + } + c.Ptrs[0] = p + c.KeepRefs = c.KeepRefs[:0] + c.SeenPtr = c.SeenPtr[:0] + c.BaseIndent = 0 +} + +func (c *RuntimeContext) Ptr() uintptr { + header := (*runtime.SliceHeader)(unsafe.Pointer(&c.Ptrs)) + return uintptr(header.Data) +} + +func AppendByteSlice(b []byte, src []byte) []byte { + if src == nil { + return append(b, `null`...) + } + encodedLen := base64.StdEncoding.EncodedLen(len(src)) + b = append(b, '"') + pos := len(b) + remainLen := cap(b[pos:]) + var buf []byte + if remainLen > encodedLen { + buf = b[pos : pos+encodedLen] + } else { + buf = make([]byte, encodedLen) + } + base64.StdEncoding.Encode(buf, src) + return append(append(b, buf...), '"') +} + +func AppendFloat32(b []byte, v float32) []byte { + f64 := float64(v) + abs := math.Abs(f64) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + f32 := float32(abs) + if f32 < 1e-6 || f32 >= 1e21 { + fmt = 'e' + } + } + return strconv.AppendFloat(b, f64, fmt, -1, 32) +} + +func AppendFloat64(b []byte, v float64) []byte { + abs := math.Abs(v) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + return strconv.AppendFloat(b, v, fmt, -1, 64) +} + +func AppendBool(b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +var ( + floatTable = [256]bool{ + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + '.': true, + 'e': true, + 'E': true, + '+': true, + '-': true, + } +) + +func AppendNumber(b []byte, n json.Number) ([]byte, error) { + if len(n) == 0 { + return append(b, '0'), nil + } + for i := 0; i < len(n); i++ { + if !floatTable[n[i]] { + return nil, fmt.Errorf("json: invalid number literal %q", n) + } + } + b = append(b, n...) + return b, nil +} + +func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if code.AddrForMarshaler { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + marshaler, ok := v.(json.Marshaler) + if !ok { + return AppendNull(b), nil + } + bb, err := marshaler.MarshalJSON() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + return bb, nil + //buf := bytes.NewBuffer(b) + //TODO: we should validate buffer with `compact` + // if err := compact(buf, bb, escape); err != nil { + // return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + // } + //return buf.Bytes(), nil +} + +func AppendMarshalText(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if code.AddrForMarshaler { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + marshaler, ok := v.(encoding.TextMarshaler) + if !ok { + return AppendNull(b), nil + } + bytes, err := marshaler.MarshalText() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + if escape { + return AppendEscapedString(b, *(*string)(unsafe.Pointer(&bytes))), nil + } + return AppendString(b, *(*string)(unsafe.Pointer(&bytes))), nil +} + +func AppendNull(b []byte) []byte { + return append(b, "null"...) +} + +func AppendComma(b []byte) []byte { + return append(b, ',') +} + +func AppendStructEnd(b []byte) []byte { + return append(b, '}', ',') +} diff --git a/internal/encoder/int.go b/internal/encoder/int.go new file mode 100644 index 0000000..70ea5f7 --- /dev/null +++ b/internal/encoder/int.go @@ -0,0 +1,124 @@ +package encoder + +import ( + "unsafe" +) + +var endianness int + +func init() { + var b [2]byte + *(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD) + + switch b[0] { + case 0xCD: + endianness = 0 // LE + case 0xAB: + endianness = 1 // BE + default: + panic("could not determine endianness") + } +} + +// "00010203...96979899" cast to []uint16 +var intLELookup = [100]uint16{ + 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, + 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, + 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, + 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, + 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, + 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, + 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, + 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, + 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, + 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939, +} + +var intBELookup = [100]uint16{ + 0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039, + 0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139, + 0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239, + 0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339, + 0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439, + 0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539, + 0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639, + 0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739, + 0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839, + 0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939, +} + +var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup} + +func AppendInt(out []byte, u64 uint64, code *Opcode) []byte { + n := u64 & code.Mask + negative := (u64>>code.RshiftNum)&1 == 1 + if !negative { + if n < 10 { + return append(out, byte(n+'0')) + } else if n < 100 { + u := intLELookup[n] + return append(out, byte(u), byte(u>>8)) + } + } else { + n = -n & code.Mask + } + + lookup := intLookup[endianness] + + var b [22]byte + u := (*[11]uint16)(unsafe.Pointer(&b)) + i := 11 + + for n >= 100 { + j := n % 100 + n /= 100 + i-- + u[i] = lookup[j] + } + + i-- + u[i] = lookup[n] + + i *= 2 // convert to byte index + if n < 10 { + i++ // remove leading zero + } + if negative { + i-- + b[i] = '-' + } + + return append(out, b[i:]...) +} + +func AppendUint(out []byte, u64 uint64, code *Opcode) []byte { + n := u64 & code.Mask + if n < 10 { + return append(out, byte(n+'0')) + } else if n < 100 { + u := intLELookup[n] + return append(out, byte(u), byte(u>>8)) + } + + lookup := intLookup[endianness] + + var b [22]byte + u := (*[11]uint16)(unsafe.Pointer(&b)) + i := 11 + + for n >= 100 { + j := n % 100 + n /= 100 + i-- + u[i] = lookup[j] + } + + i-- + u[i] = lookup[n] + + i *= 2 // convert to byte index + if n < 10 { + i++ // remove leading zero + } + return append(out, b[i:]...) +} diff --git a/internal/encoder/map112.go b/internal/encoder/map112.go new file mode 100644 index 0000000..31858d0 --- /dev/null +++ b/internal/encoder/map112.go @@ -0,0 +1,8 @@ +// +build !go1.13 + +package encoder + +import "unsafe" + +//go:linkname MapIterValue reflect.mapitervalue +func MapIterValue(it unsafe.Pointer) unsafe.Pointer diff --git a/internal/encoder/map113.go b/internal/encoder/map113.go new file mode 100644 index 0000000..f49c27b --- /dev/null +++ b/internal/encoder/map113.go @@ -0,0 +1,8 @@ +// +build go1.13 + +package encoder + +import "unsafe" + +//go:linkname MapIterValue reflect.mapiterelem +func MapIterValue(it unsafe.Pointer) unsafe.Pointer diff --git a/internal/encoder/optype.go b/internal/encoder/optype.go new file mode 100644 index 0000000..b0641c2 --- /dev/null +++ b/internal/encoder/optype.go @@ -0,0 +1,1025 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package encoder + +import ( + "strings" +) + +type CodeType int + +const ( + CodeOp CodeType = 0 + CodeArrayHead CodeType = 1 + CodeArrayElem CodeType = 2 + CodeSliceHead CodeType = 3 + CodeSliceElem CodeType = 4 + CodeMapHead CodeType = 5 + CodeMapKey CodeType = 6 + CodeMapValue CodeType = 7 + CodeMapEnd CodeType = 8 + CodeStructFieldRecursive CodeType = 9 + CodeStructField CodeType = 10 + CodeStructEnd CodeType = 11 +) + +var opTypeStrings = [440]string{ + "End", + "Interface", + "Ptr", + "SliceElem", + "SliceEnd", + "ArrayElem", + "ArrayEnd", + "MapKey", + "MapValue", + "MapEnd", + "StructFieldRecursiveEnd", + "StructAnonymousEnd", + "Int", + "Uint", + "Float32", + "Float64", + "Bool", + "String", + "Bytes", + "Number", + "Array", + "Map", + "Slice", + "Struct", + "MarshalJSON", + "MarshalText", + "Recursive", + "IntString", + "UintString", + "IntPtr", + "UintPtr", + "Float32Ptr", + "Float64Ptr", + "BoolPtr", + "StringPtr", + "BytesPtr", + "NumberPtr", + "ArrayPtr", + "MapPtr", + "SlicePtr", + "MarshalJSONPtr", + "MarshalTextPtr", + "InterfacePtr", + "RecursivePtr", + "StructHeadInt", + "StructHeadOmitEmptyInt", + "StructHeadStringTagInt", + "StructPtrHeadInt", + "StructPtrHeadOmitEmptyInt", + "StructPtrHeadStringTagInt", + "StructHeadUint", + "StructHeadOmitEmptyUint", + "StructHeadStringTagUint", + "StructPtrHeadUint", + "StructPtrHeadOmitEmptyUint", + "StructPtrHeadStringTagUint", + "StructHeadFloat32", + "StructHeadOmitEmptyFloat32", + "StructHeadStringTagFloat32", + "StructPtrHeadFloat32", + "StructPtrHeadOmitEmptyFloat32", + "StructPtrHeadStringTagFloat32", + "StructHeadFloat64", + "StructHeadOmitEmptyFloat64", + "StructHeadStringTagFloat64", + "StructPtrHeadFloat64", + "StructPtrHeadOmitEmptyFloat64", + "StructPtrHeadStringTagFloat64", + "StructHeadBool", + "StructHeadOmitEmptyBool", + "StructHeadStringTagBool", + "StructPtrHeadBool", + "StructPtrHeadOmitEmptyBool", + "StructPtrHeadStringTagBool", + "StructHeadString", + "StructHeadOmitEmptyString", + "StructHeadStringTagString", + "StructPtrHeadString", + "StructPtrHeadOmitEmptyString", + "StructPtrHeadStringTagString", + "StructHeadBytes", + "StructHeadOmitEmptyBytes", + "StructHeadStringTagBytes", + "StructPtrHeadBytes", + "StructPtrHeadOmitEmptyBytes", + "StructPtrHeadStringTagBytes", + "StructHeadNumber", + "StructHeadOmitEmptyNumber", + "StructHeadStringTagNumber", + "StructPtrHeadNumber", + "StructPtrHeadOmitEmptyNumber", + "StructPtrHeadStringTagNumber", + "StructHeadArray", + "StructHeadOmitEmptyArray", + "StructHeadStringTagArray", + "StructPtrHeadArray", + "StructPtrHeadOmitEmptyArray", + "StructPtrHeadStringTagArray", + "StructHeadMap", + "StructHeadOmitEmptyMap", + "StructHeadStringTagMap", + "StructPtrHeadMap", + "StructPtrHeadOmitEmptyMap", + "StructPtrHeadStringTagMap", + "StructHeadSlice", + "StructHeadOmitEmptySlice", + "StructHeadStringTagSlice", + "StructPtrHeadSlice", + "StructPtrHeadOmitEmptySlice", + "StructPtrHeadStringTagSlice", + "StructHeadStruct", + "StructHeadOmitEmptyStruct", + "StructHeadStringTagStruct", + "StructPtrHeadStruct", + "StructPtrHeadOmitEmptyStruct", + "StructPtrHeadStringTagStruct", + "StructHeadMarshalJSON", + "StructHeadOmitEmptyMarshalJSON", + "StructHeadStringTagMarshalJSON", + "StructPtrHeadMarshalJSON", + "StructPtrHeadOmitEmptyMarshalJSON", + "StructPtrHeadStringTagMarshalJSON", + "StructHeadMarshalText", + "StructHeadOmitEmptyMarshalText", + "StructHeadStringTagMarshalText", + "StructPtrHeadMarshalText", + "StructPtrHeadOmitEmptyMarshalText", + "StructPtrHeadStringTagMarshalText", + "StructHeadRecursive", + "StructHeadOmitEmptyRecursive", + "StructHeadStringTagRecursive", + "StructPtrHeadRecursive", + "StructPtrHeadOmitEmptyRecursive", + "StructPtrHeadStringTagRecursive", + "StructHeadIntString", + "StructHeadOmitEmptyIntString", + "StructHeadStringTagIntString", + "StructPtrHeadIntString", + "StructPtrHeadOmitEmptyIntString", + "StructPtrHeadStringTagIntString", + "StructHeadUintString", + "StructHeadOmitEmptyUintString", + "StructHeadStringTagUintString", + "StructPtrHeadUintString", + "StructPtrHeadOmitEmptyUintString", + "StructPtrHeadStringTagUintString", + "StructHeadIntPtr", + "StructHeadOmitEmptyIntPtr", + "StructHeadStringTagIntPtr", + "StructPtrHeadIntPtr", + "StructPtrHeadOmitEmptyIntPtr", + "StructPtrHeadStringTagIntPtr", + "StructHeadUintPtr", + "StructHeadOmitEmptyUintPtr", + "StructHeadStringTagUintPtr", + "StructPtrHeadUintPtr", + "StructPtrHeadOmitEmptyUintPtr", + "StructPtrHeadStringTagUintPtr", + "StructHeadFloat32Ptr", + "StructHeadOmitEmptyFloat32Ptr", + "StructHeadStringTagFloat32Ptr", + "StructPtrHeadFloat32Ptr", + "StructPtrHeadOmitEmptyFloat32Ptr", + "StructPtrHeadStringTagFloat32Ptr", + "StructHeadFloat64Ptr", + "StructHeadOmitEmptyFloat64Ptr", + "StructHeadStringTagFloat64Ptr", + "StructPtrHeadFloat64Ptr", + "StructPtrHeadOmitEmptyFloat64Ptr", + "StructPtrHeadStringTagFloat64Ptr", + "StructHeadBoolPtr", + "StructHeadOmitEmptyBoolPtr", + "StructHeadStringTagBoolPtr", + "StructPtrHeadBoolPtr", + "StructPtrHeadOmitEmptyBoolPtr", + "StructPtrHeadStringTagBoolPtr", + "StructHeadStringPtr", + "StructHeadOmitEmptyStringPtr", + "StructHeadStringTagStringPtr", + "StructPtrHeadStringPtr", + "StructPtrHeadOmitEmptyStringPtr", + "StructPtrHeadStringTagStringPtr", + "StructHeadBytesPtr", + "StructHeadOmitEmptyBytesPtr", + "StructHeadStringTagBytesPtr", + "StructPtrHeadBytesPtr", + "StructPtrHeadOmitEmptyBytesPtr", + "StructPtrHeadStringTagBytesPtr", + "StructHeadNumberPtr", + "StructHeadOmitEmptyNumberPtr", + "StructHeadStringTagNumberPtr", + "StructPtrHeadNumberPtr", + "StructPtrHeadOmitEmptyNumberPtr", + "StructPtrHeadStringTagNumberPtr", + "StructHeadArrayPtr", + "StructHeadOmitEmptyArrayPtr", + "StructHeadStringTagArrayPtr", + "StructPtrHeadArrayPtr", + "StructPtrHeadOmitEmptyArrayPtr", + "StructPtrHeadStringTagArrayPtr", + "StructHeadMapPtr", + "StructHeadOmitEmptyMapPtr", + "StructHeadStringTagMapPtr", + "StructPtrHeadMapPtr", + "StructPtrHeadOmitEmptyMapPtr", + "StructPtrHeadStringTagMapPtr", + "StructHeadSlicePtr", + "StructHeadOmitEmptySlicePtr", + "StructHeadStringTagSlicePtr", + "StructPtrHeadSlicePtr", + "StructPtrHeadOmitEmptySlicePtr", + "StructPtrHeadStringTagSlicePtr", + "StructHeadMarshalJSONPtr", + "StructHeadOmitEmptyMarshalJSONPtr", + "StructHeadStringTagMarshalJSONPtr", + "StructPtrHeadMarshalJSONPtr", + "StructPtrHeadOmitEmptyMarshalJSONPtr", + "StructPtrHeadStringTagMarshalJSONPtr", + "StructHeadMarshalTextPtr", + "StructHeadOmitEmptyMarshalTextPtr", + "StructHeadStringTagMarshalTextPtr", + "StructPtrHeadMarshalTextPtr", + "StructPtrHeadOmitEmptyMarshalTextPtr", + "StructPtrHeadStringTagMarshalTextPtr", + "StructHeadInterfacePtr", + "StructHeadOmitEmptyInterfacePtr", + "StructHeadStringTagInterfacePtr", + "StructPtrHeadInterfacePtr", + "StructPtrHeadOmitEmptyInterfacePtr", + "StructPtrHeadStringTagInterfacePtr", + "StructHeadRecursivePtr", + "StructHeadOmitEmptyRecursivePtr", + "StructHeadStringTagRecursivePtr", + "StructPtrHeadRecursivePtr", + "StructPtrHeadOmitEmptyRecursivePtr", + "StructPtrHeadStringTagRecursivePtr", + "StructHead", + "StructHeadOmitEmpty", + "StructHeadStringTag", + "StructPtrHead", + "StructPtrHeadOmitEmpty", + "StructPtrHeadStringTag", + "StructFieldInt", + "StructFieldOmitEmptyInt", + "StructFieldStringTagInt", + "StructEndInt", + "StructEndOmitEmptyInt", + "StructEndStringTagInt", + "StructFieldUint", + "StructFieldOmitEmptyUint", + "StructFieldStringTagUint", + "StructEndUint", + "StructEndOmitEmptyUint", + "StructEndStringTagUint", + "StructFieldFloat32", + "StructFieldOmitEmptyFloat32", + "StructFieldStringTagFloat32", + "StructEndFloat32", + "StructEndOmitEmptyFloat32", + "StructEndStringTagFloat32", + "StructFieldFloat64", + "StructFieldOmitEmptyFloat64", + "StructFieldStringTagFloat64", + "StructEndFloat64", + "StructEndOmitEmptyFloat64", + "StructEndStringTagFloat64", + "StructFieldBool", + "StructFieldOmitEmptyBool", + "StructFieldStringTagBool", + "StructEndBool", + "StructEndOmitEmptyBool", + "StructEndStringTagBool", + "StructFieldString", + "StructFieldOmitEmptyString", + "StructFieldStringTagString", + "StructEndString", + "StructEndOmitEmptyString", + "StructEndStringTagString", + "StructFieldBytes", + "StructFieldOmitEmptyBytes", + "StructFieldStringTagBytes", + "StructEndBytes", + "StructEndOmitEmptyBytes", + "StructEndStringTagBytes", + "StructFieldNumber", + "StructFieldOmitEmptyNumber", + "StructFieldStringTagNumber", + "StructEndNumber", + "StructEndOmitEmptyNumber", + "StructEndStringTagNumber", + "StructFieldArray", + "StructFieldOmitEmptyArray", + "StructFieldStringTagArray", + "StructEndArray", + "StructEndOmitEmptyArray", + "StructEndStringTagArray", + "StructFieldMap", + "StructFieldOmitEmptyMap", + "StructFieldStringTagMap", + "StructEndMap", + "StructEndOmitEmptyMap", + "StructEndStringTagMap", + "StructFieldSlice", + "StructFieldOmitEmptySlice", + "StructFieldStringTagSlice", + "StructEndSlice", + "StructEndOmitEmptySlice", + "StructEndStringTagSlice", + "StructFieldStruct", + "StructFieldOmitEmptyStruct", + "StructFieldStringTagStruct", + "StructEndStruct", + "StructEndOmitEmptyStruct", + "StructEndStringTagStruct", + "StructFieldMarshalJSON", + "StructFieldOmitEmptyMarshalJSON", + "StructFieldStringTagMarshalJSON", + "StructEndMarshalJSON", + "StructEndOmitEmptyMarshalJSON", + "StructEndStringTagMarshalJSON", + "StructFieldMarshalText", + "StructFieldOmitEmptyMarshalText", + "StructFieldStringTagMarshalText", + "StructEndMarshalText", + "StructEndOmitEmptyMarshalText", + "StructEndStringTagMarshalText", + "StructFieldRecursive", + "StructFieldOmitEmptyRecursive", + "StructFieldStringTagRecursive", + "StructEndRecursive", + "StructEndOmitEmptyRecursive", + "StructEndStringTagRecursive", + "StructFieldIntString", + "StructFieldOmitEmptyIntString", + "StructFieldStringTagIntString", + "StructEndIntString", + "StructEndOmitEmptyIntString", + "StructEndStringTagIntString", + "StructFieldUintString", + "StructFieldOmitEmptyUintString", + "StructFieldStringTagUintString", + "StructEndUintString", + "StructEndOmitEmptyUintString", + "StructEndStringTagUintString", + "StructFieldIntPtr", + "StructFieldOmitEmptyIntPtr", + "StructFieldStringTagIntPtr", + "StructEndIntPtr", + "StructEndOmitEmptyIntPtr", + "StructEndStringTagIntPtr", + "StructFieldUintPtr", + "StructFieldOmitEmptyUintPtr", + "StructFieldStringTagUintPtr", + "StructEndUintPtr", + "StructEndOmitEmptyUintPtr", + "StructEndStringTagUintPtr", + "StructFieldFloat32Ptr", + "StructFieldOmitEmptyFloat32Ptr", + "StructFieldStringTagFloat32Ptr", + "StructEndFloat32Ptr", + "StructEndOmitEmptyFloat32Ptr", + "StructEndStringTagFloat32Ptr", + "StructFieldFloat64Ptr", + "StructFieldOmitEmptyFloat64Ptr", + "StructFieldStringTagFloat64Ptr", + "StructEndFloat64Ptr", + "StructEndOmitEmptyFloat64Ptr", + "StructEndStringTagFloat64Ptr", + "StructFieldBoolPtr", + "StructFieldOmitEmptyBoolPtr", + "StructFieldStringTagBoolPtr", + "StructEndBoolPtr", + "StructEndOmitEmptyBoolPtr", + "StructEndStringTagBoolPtr", + "StructFieldStringPtr", + "StructFieldOmitEmptyStringPtr", + "StructFieldStringTagStringPtr", + "StructEndStringPtr", + "StructEndOmitEmptyStringPtr", + "StructEndStringTagStringPtr", + "StructFieldBytesPtr", + "StructFieldOmitEmptyBytesPtr", + "StructFieldStringTagBytesPtr", + "StructEndBytesPtr", + "StructEndOmitEmptyBytesPtr", + "StructEndStringTagBytesPtr", + "StructFieldNumberPtr", + "StructFieldOmitEmptyNumberPtr", + "StructFieldStringTagNumberPtr", + "StructEndNumberPtr", + "StructEndOmitEmptyNumberPtr", + "StructEndStringTagNumberPtr", + "StructFieldArrayPtr", + "StructFieldOmitEmptyArrayPtr", + "StructFieldStringTagArrayPtr", + "StructEndArrayPtr", + "StructEndOmitEmptyArrayPtr", + "StructEndStringTagArrayPtr", + "StructFieldMapPtr", + "StructFieldOmitEmptyMapPtr", + "StructFieldStringTagMapPtr", + "StructEndMapPtr", + "StructEndOmitEmptyMapPtr", + "StructEndStringTagMapPtr", + "StructFieldSlicePtr", + "StructFieldOmitEmptySlicePtr", + "StructFieldStringTagSlicePtr", + "StructEndSlicePtr", + "StructEndOmitEmptySlicePtr", + "StructEndStringTagSlicePtr", + "StructFieldMarshalJSONPtr", + "StructFieldOmitEmptyMarshalJSONPtr", + "StructFieldStringTagMarshalJSONPtr", + "StructEndMarshalJSONPtr", + "StructEndOmitEmptyMarshalJSONPtr", + "StructEndStringTagMarshalJSONPtr", + "StructFieldMarshalTextPtr", + "StructFieldOmitEmptyMarshalTextPtr", + "StructFieldStringTagMarshalTextPtr", + "StructEndMarshalTextPtr", + "StructEndOmitEmptyMarshalTextPtr", + "StructEndStringTagMarshalTextPtr", + "StructFieldInterfacePtr", + "StructFieldOmitEmptyInterfacePtr", + "StructFieldStringTagInterfacePtr", + "StructEndInterfacePtr", + "StructEndOmitEmptyInterfacePtr", + "StructEndStringTagInterfacePtr", + "StructFieldRecursivePtr", + "StructFieldOmitEmptyRecursivePtr", + "StructFieldStringTagRecursivePtr", + "StructEndRecursivePtr", + "StructEndOmitEmptyRecursivePtr", + "StructEndStringTagRecursivePtr", + "StructField", + "StructFieldOmitEmpty", + "StructFieldStringTag", + "StructEnd", + "StructEndOmitEmpty", + "StructEndStringTag", +} + +type OpType int + +const ( + OpEnd OpType = 0 + OpInterface OpType = 1 + OpPtr OpType = 2 + OpSliceElem OpType = 3 + OpSliceEnd OpType = 4 + OpArrayElem OpType = 5 + OpArrayEnd OpType = 6 + OpMapKey OpType = 7 + OpMapValue OpType = 8 + OpMapEnd OpType = 9 + OpStructFieldRecursiveEnd OpType = 10 + OpStructAnonymousEnd OpType = 11 + OpInt OpType = 12 + OpUint OpType = 13 + OpFloat32 OpType = 14 + OpFloat64 OpType = 15 + OpBool OpType = 16 + OpString OpType = 17 + OpBytes OpType = 18 + OpNumber OpType = 19 + OpArray OpType = 20 + OpMap OpType = 21 + OpSlice OpType = 22 + OpStruct OpType = 23 + OpMarshalJSON OpType = 24 + OpMarshalText OpType = 25 + OpRecursive OpType = 26 + OpIntString OpType = 27 + OpUintString OpType = 28 + OpIntPtr OpType = 29 + OpUintPtr OpType = 30 + OpFloat32Ptr OpType = 31 + OpFloat64Ptr OpType = 32 + OpBoolPtr OpType = 33 + OpStringPtr OpType = 34 + OpBytesPtr OpType = 35 + OpNumberPtr OpType = 36 + OpArrayPtr OpType = 37 + OpMapPtr OpType = 38 + OpSlicePtr OpType = 39 + OpMarshalJSONPtr OpType = 40 + OpMarshalTextPtr OpType = 41 + OpInterfacePtr OpType = 42 + OpRecursivePtr OpType = 43 + OpStructHeadInt OpType = 44 + OpStructHeadOmitEmptyInt OpType = 45 + OpStructHeadStringTagInt OpType = 46 + OpStructPtrHeadInt OpType = 47 + OpStructPtrHeadOmitEmptyInt OpType = 48 + OpStructPtrHeadStringTagInt OpType = 49 + OpStructHeadUint OpType = 50 + OpStructHeadOmitEmptyUint OpType = 51 + OpStructHeadStringTagUint OpType = 52 + OpStructPtrHeadUint OpType = 53 + OpStructPtrHeadOmitEmptyUint OpType = 54 + OpStructPtrHeadStringTagUint OpType = 55 + OpStructHeadFloat32 OpType = 56 + OpStructHeadOmitEmptyFloat32 OpType = 57 + OpStructHeadStringTagFloat32 OpType = 58 + OpStructPtrHeadFloat32 OpType = 59 + OpStructPtrHeadOmitEmptyFloat32 OpType = 60 + OpStructPtrHeadStringTagFloat32 OpType = 61 + OpStructHeadFloat64 OpType = 62 + OpStructHeadOmitEmptyFloat64 OpType = 63 + OpStructHeadStringTagFloat64 OpType = 64 + OpStructPtrHeadFloat64 OpType = 65 + OpStructPtrHeadOmitEmptyFloat64 OpType = 66 + OpStructPtrHeadStringTagFloat64 OpType = 67 + OpStructHeadBool OpType = 68 + OpStructHeadOmitEmptyBool OpType = 69 + OpStructHeadStringTagBool OpType = 70 + OpStructPtrHeadBool OpType = 71 + OpStructPtrHeadOmitEmptyBool OpType = 72 + OpStructPtrHeadStringTagBool OpType = 73 + OpStructHeadString OpType = 74 + OpStructHeadOmitEmptyString OpType = 75 + OpStructHeadStringTagString OpType = 76 + OpStructPtrHeadString OpType = 77 + OpStructPtrHeadOmitEmptyString OpType = 78 + OpStructPtrHeadStringTagString OpType = 79 + OpStructHeadBytes OpType = 80 + OpStructHeadOmitEmptyBytes OpType = 81 + OpStructHeadStringTagBytes OpType = 82 + OpStructPtrHeadBytes OpType = 83 + OpStructPtrHeadOmitEmptyBytes OpType = 84 + OpStructPtrHeadStringTagBytes OpType = 85 + OpStructHeadNumber OpType = 86 + OpStructHeadOmitEmptyNumber OpType = 87 + OpStructHeadStringTagNumber OpType = 88 + OpStructPtrHeadNumber OpType = 89 + OpStructPtrHeadOmitEmptyNumber OpType = 90 + OpStructPtrHeadStringTagNumber OpType = 91 + OpStructHeadArray OpType = 92 + OpStructHeadOmitEmptyArray OpType = 93 + OpStructHeadStringTagArray OpType = 94 + OpStructPtrHeadArray OpType = 95 + OpStructPtrHeadOmitEmptyArray OpType = 96 + OpStructPtrHeadStringTagArray OpType = 97 + OpStructHeadMap OpType = 98 + OpStructHeadOmitEmptyMap OpType = 99 + OpStructHeadStringTagMap OpType = 100 + OpStructPtrHeadMap OpType = 101 + OpStructPtrHeadOmitEmptyMap OpType = 102 + OpStructPtrHeadStringTagMap OpType = 103 + OpStructHeadSlice OpType = 104 + OpStructHeadOmitEmptySlice OpType = 105 + OpStructHeadStringTagSlice OpType = 106 + OpStructPtrHeadSlice OpType = 107 + OpStructPtrHeadOmitEmptySlice OpType = 108 + OpStructPtrHeadStringTagSlice OpType = 109 + OpStructHeadStruct OpType = 110 + OpStructHeadOmitEmptyStruct OpType = 111 + OpStructHeadStringTagStruct OpType = 112 + OpStructPtrHeadStruct OpType = 113 + OpStructPtrHeadOmitEmptyStruct OpType = 114 + OpStructPtrHeadStringTagStruct OpType = 115 + OpStructHeadMarshalJSON OpType = 116 + OpStructHeadOmitEmptyMarshalJSON OpType = 117 + OpStructHeadStringTagMarshalJSON OpType = 118 + OpStructPtrHeadMarshalJSON OpType = 119 + OpStructPtrHeadOmitEmptyMarshalJSON OpType = 120 + OpStructPtrHeadStringTagMarshalJSON OpType = 121 + OpStructHeadMarshalText OpType = 122 + OpStructHeadOmitEmptyMarshalText OpType = 123 + OpStructHeadStringTagMarshalText OpType = 124 + OpStructPtrHeadMarshalText OpType = 125 + OpStructPtrHeadOmitEmptyMarshalText OpType = 126 + OpStructPtrHeadStringTagMarshalText OpType = 127 + OpStructHeadRecursive OpType = 128 + OpStructHeadOmitEmptyRecursive OpType = 129 + OpStructHeadStringTagRecursive OpType = 130 + OpStructPtrHeadRecursive OpType = 131 + OpStructPtrHeadOmitEmptyRecursive OpType = 132 + OpStructPtrHeadStringTagRecursive OpType = 133 + OpStructHeadIntString OpType = 134 + OpStructHeadOmitEmptyIntString OpType = 135 + OpStructHeadStringTagIntString OpType = 136 + OpStructPtrHeadIntString OpType = 137 + OpStructPtrHeadOmitEmptyIntString OpType = 138 + OpStructPtrHeadStringTagIntString OpType = 139 + OpStructHeadUintString OpType = 140 + OpStructHeadOmitEmptyUintString OpType = 141 + OpStructHeadStringTagUintString OpType = 142 + OpStructPtrHeadUintString OpType = 143 + OpStructPtrHeadOmitEmptyUintString OpType = 144 + OpStructPtrHeadStringTagUintString OpType = 145 + OpStructHeadIntPtr OpType = 146 + OpStructHeadOmitEmptyIntPtr OpType = 147 + OpStructHeadStringTagIntPtr OpType = 148 + OpStructPtrHeadIntPtr OpType = 149 + OpStructPtrHeadOmitEmptyIntPtr OpType = 150 + OpStructPtrHeadStringTagIntPtr OpType = 151 + OpStructHeadUintPtr OpType = 152 + OpStructHeadOmitEmptyUintPtr OpType = 153 + OpStructHeadStringTagUintPtr OpType = 154 + OpStructPtrHeadUintPtr OpType = 155 + OpStructPtrHeadOmitEmptyUintPtr OpType = 156 + OpStructPtrHeadStringTagUintPtr OpType = 157 + OpStructHeadFloat32Ptr OpType = 158 + OpStructHeadOmitEmptyFloat32Ptr OpType = 159 + OpStructHeadStringTagFloat32Ptr OpType = 160 + OpStructPtrHeadFloat32Ptr OpType = 161 + OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 162 + OpStructPtrHeadStringTagFloat32Ptr OpType = 163 + OpStructHeadFloat64Ptr OpType = 164 + OpStructHeadOmitEmptyFloat64Ptr OpType = 165 + OpStructHeadStringTagFloat64Ptr OpType = 166 + OpStructPtrHeadFloat64Ptr OpType = 167 + OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 168 + OpStructPtrHeadStringTagFloat64Ptr OpType = 169 + OpStructHeadBoolPtr OpType = 170 + OpStructHeadOmitEmptyBoolPtr OpType = 171 + OpStructHeadStringTagBoolPtr OpType = 172 + OpStructPtrHeadBoolPtr OpType = 173 + OpStructPtrHeadOmitEmptyBoolPtr OpType = 174 + OpStructPtrHeadStringTagBoolPtr OpType = 175 + OpStructHeadStringPtr OpType = 176 + OpStructHeadOmitEmptyStringPtr OpType = 177 + OpStructHeadStringTagStringPtr OpType = 178 + OpStructPtrHeadStringPtr OpType = 179 + OpStructPtrHeadOmitEmptyStringPtr OpType = 180 + OpStructPtrHeadStringTagStringPtr OpType = 181 + OpStructHeadBytesPtr OpType = 182 + OpStructHeadOmitEmptyBytesPtr OpType = 183 + OpStructHeadStringTagBytesPtr OpType = 184 + OpStructPtrHeadBytesPtr OpType = 185 + OpStructPtrHeadOmitEmptyBytesPtr OpType = 186 + OpStructPtrHeadStringTagBytesPtr OpType = 187 + OpStructHeadNumberPtr OpType = 188 + OpStructHeadOmitEmptyNumberPtr OpType = 189 + OpStructHeadStringTagNumberPtr OpType = 190 + OpStructPtrHeadNumberPtr OpType = 191 + OpStructPtrHeadOmitEmptyNumberPtr OpType = 192 + OpStructPtrHeadStringTagNumberPtr OpType = 193 + OpStructHeadArrayPtr OpType = 194 + OpStructHeadOmitEmptyArrayPtr OpType = 195 + OpStructHeadStringTagArrayPtr OpType = 196 + OpStructPtrHeadArrayPtr OpType = 197 + OpStructPtrHeadOmitEmptyArrayPtr OpType = 198 + OpStructPtrHeadStringTagArrayPtr OpType = 199 + OpStructHeadMapPtr OpType = 200 + OpStructHeadOmitEmptyMapPtr OpType = 201 + OpStructHeadStringTagMapPtr OpType = 202 + OpStructPtrHeadMapPtr OpType = 203 + OpStructPtrHeadOmitEmptyMapPtr OpType = 204 + OpStructPtrHeadStringTagMapPtr OpType = 205 + OpStructHeadSlicePtr OpType = 206 + OpStructHeadOmitEmptySlicePtr OpType = 207 + OpStructHeadStringTagSlicePtr OpType = 208 + OpStructPtrHeadSlicePtr OpType = 209 + OpStructPtrHeadOmitEmptySlicePtr OpType = 210 + OpStructPtrHeadStringTagSlicePtr OpType = 211 + OpStructHeadMarshalJSONPtr OpType = 212 + OpStructHeadOmitEmptyMarshalJSONPtr OpType = 213 + OpStructHeadStringTagMarshalJSONPtr OpType = 214 + OpStructPtrHeadMarshalJSONPtr OpType = 215 + OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 216 + OpStructPtrHeadStringTagMarshalJSONPtr OpType = 217 + OpStructHeadMarshalTextPtr OpType = 218 + OpStructHeadOmitEmptyMarshalTextPtr OpType = 219 + OpStructHeadStringTagMarshalTextPtr OpType = 220 + OpStructPtrHeadMarshalTextPtr OpType = 221 + OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 222 + OpStructPtrHeadStringTagMarshalTextPtr OpType = 223 + OpStructHeadInterfacePtr OpType = 224 + OpStructHeadOmitEmptyInterfacePtr OpType = 225 + OpStructHeadStringTagInterfacePtr OpType = 226 + OpStructPtrHeadInterfacePtr OpType = 227 + OpStructPtrHeadOmitEmptyInterfacePtr OpType = 228 + OpStructPtrHeadStringTagInterfacePtr OpType = 229 + OpStructHeadRecursivePtr OpType = 230 + OpStructHeadOmitEmptyRecursivePtr OpType = 231 + OpStructHeadStringTagRecursivePtr OpType = 232 + OpStructPtrHeadRecursivePtr OpType = 233 + OpStructPtrHeadOmitEmptyRecursivePtr OpType = 234 + OpStructPtrHeadStringTagRecursivePtr OpType = 235 + OpStructHead OpType = 236 + OpStructHeadOmitEmpty OpType = 237 + OpStructHeadStringTag OpType = 238 + OpStructPtrHead OpType = 239 + OpStructPtrHeadOmitEmpty OpType = 240 + OpStructPtrHeadStringTag OpType = 241 + OpStructFieldInt OpType = 242 + OpStructFieldOmitEmptyInt OpType = 243 + OpStructFieldStringTagInt OpType = 244 + OpStructEndInt OpType = 245 + OpStructEndOmitEmptyInt OpType = 246 + OpStructEndStringTagInt OpType = 247 + OpStructFieldUint OpType = 248 + OpStructFieldOmitEmptyUint OpType = 249 + OpStructFieldStringTagUint OpType = 250 + OpStructEndUint OpType = 251 + OpStructEndOmitEmptyUint OpType = 252 + OpStructEndStringTagUint OpType = 253 + OpStructFieldFloat32 OpType = 254 + OpStructFieldOmitEmptyFloat32 OpType = 255 + OpStructFieldStringTagFloat32 OpType = 256 + OpStructEndFloat32 OpType = 257 + OpStructEndOmitEmptyFloat32 OpType = 258 + OpStructEndStringTagFloat32 OpType = 259 + OpStructFieldFloat64 OpType = 260 + OpStructFieldOmitEmptyFloat64 OpType = 261 + OpStructFieldStringTagFloat64 OpType = 262 + OpStructEndFloat64 OpType = 263 + OpStructEndOmitEmptyFloat64 OpType = 264 + OpStructEndStringTagFloat64 OpType = 265 + OpStructFieldBool OpType = 266 + OpStructFieldOmitEmptyBool OpType = 267 + OpStructFieldStringTagBool OpType = 268 + OpStructEndBool OpType = 269 + OpStructEndOmitEmptyBool OpType = 270 + OpStructEndStringTagBool OpType = 271 + OpStructFieldString OpType = 272 + OpStructFieldOmitEmptyString OpType = 273 + OpStructFieldStringTagString OpType = 274 + OpStructEndString OpType = 275 + OpStructEndOmitEmptyString OpType = 276 + OpStructEndStringTagString OpType = 277 + OpStructFieldBytes OpType = 278 + OpStructFieldOmitEmptyBytes OpType = 279 + OpStructFieldStringTagBytes OpType = 280 + OpStructEndBytes OpType = 281 + OpStructEndOmitEmptyBytes OpType = 282 + OpStructEndStringTagBytes OpType = 283 + OpStructFieldNumber OpType = 284 + OpStructFieldOmitEmptyNumber OpType = 285 + OpStructFieldStringTagNumber OpType = 286 + OpStructEndNumber OpType = 287 + OpStructEndOmitEmptyNumber OpType = 288 + OpStructEndStringTagNumber OpType = 289 + OpStructFieldArray OpType = 290 + OpStructFieldOmitEmptyArray OpType = 291 + OpStructFieldStringTagArray OpType = 292 + OpStructEndArray OpType = 293 + OpStructEndOmitEmptyArray OpType = 294 + OpStructEndStringTagArray OpType = 295 + OpStructFieldMap OpType = 296 + OpStructFieldOmitEmptyMap OpType = 297 + OpStructFieldStringTagMap OpType = 298 + OpStructEndMap OpType = 299 + OpStructEndOmitEmptyMap OpType = 300 + OpStructEndStringTagMap OpType = 301 + OpStructFieldSlice OpType = 302 + OpStructFieldOmitEmptySlice OpType = 303 + OpStructFieldStringTagSlice OpType = 304 + OpStructEndSlice OpType = 305 + OpStructEndOmitEmptySlice OpType = 306 + OpStructEndStringTagSlice OpType = 307 + OpStructFieldStruct OpType = 308 + OpStructFieldOmitEmptyStruct OpType = 309 + OpStructFieldStringTagStruct OpType = 310 + OpStructEndStruct OpType = 311 + OpStructEndOmitEmptyStruct OpType = 312 + OpStructEndStringTagStruct OpType = 313 + OpStructFieldMarshalJSON OpType = 314 + OpStructFieldOmitEmptyMarshalJSON OpType = 315 + OpStructFieldStringTagMarshalJSON OpType = 316 + OpStructEndMarshalJSON OpType = 317 + OpStructEndOmitEmptyMarshalJSON OpType = 318 + OpStructEndStringTagMarshalJSON OpType = 319 + OpStructFieldMarshalText OpType = 320 + OpStructFieldOmitEmptyMarshalText OpType = 321 + OpStructFieldStringTagMarshalText OpType = 322 + OpStructEndMarshalText OpType = 323 + OpStructEndOmitEmptyMarshalText OpType = 324 + OpStructEndStringTagMarshalText OpType = 325 + OpStructFieldRecursive OpType = 326 + OpStructFieldOmitEmptyRecursive OpType = 327 + OpStructFieldStringTagRecursive OpType = 328 + OpStructEndRecursive OpType = 329 + OpStructEndOmitEmptyRecursive OpType = 330 + OpStructEndStringTagRecursive OpType = 331 + OpStructFieldIntString OpType = 332 + OpStructFieldOmitEmptyIntString OpType = 333 + OpStructFieldStringTagIntString OpType = 334 + OpStructEndIntString OpType = 335 + OpStructEndOmitEmptyIntString OpType = 336 + OpStructEndStringTagIntString OpType = 337 + OpStructFieldUintString OpType = 338 + OpStructFieldOmitEmptyUintString OpType = 339 + OpStructFieldStringTagUintString OpType = 340 + OpStructEndUintString OpType = 341 + OpStructEndOmitEmptyUintString OpType = 342 + OpStructEndStringTagUintString OpType = 343 + OpStructFieldIntPtr OpType = 344 + OpStructFieldOmitEmptyIntPtr OpType = 345 + OpStructFieldStringTagIntPtr OpType = 346 + OpStructEndIntPtr OpType = 347 + OpStructEndOmitEmptyIntPtr OpType = 348 + OpStructEndStringTagIntPtr OpType = 349 + OpStructFieldUintPtr OpType = 350 + OpStructFieldOmitEmptyUintPtr OpType = 351 + OpStructFieldStringTagUintPtr OpType = 352 + OpStructEndUintPtr OpType = 353 + OpStructEndOmitEmptyUintPtr OpType = 354 + OpStructEndStringTagUintPtr OpType = 355 + OpStructFieldFloat32Ptr OpType = 356 + OpStructFieldOmitEmptyFloat32Ptr OpType = 357 + OpStructFieldStringTagFloat32Ptr OpType = 358 + OpStructEndFloat32Ptr OpType = 359 + OpStructEndOmitEmptyFloat32Ptr OpType = 360 + OpStructEndStringTagFloat32Ptr OpType = 361 + OpStructFieldFloat64Ptr OpType = 362 + OpStructFieldOmitEmptyFloat64Ptr OpType = 363 + OpStructFieldStringTagFloat64Ptr OpType = 364 + OpStructEndFloat64Ptr OpType = 365 + OpStructEndOmitEmptyFloat64Ptr OpType = 366 + OpStructEndStringTagFloat64Ptr OpType = 367 + OpStructFieldBoolPtr OpType = 368 + OpStructFieldOmitEmptyBoolPtr OpType = 369 + OpStructFieldStringTagBoolPtr OpType = 370 + OpStructEndBoolPtr OpType = 371 + OpStructEndOmitEmptyBoolPtr OpType = 372 + OpStructEndStringTagBoolPtr OpType = 373 + OpStructFieldStringPtr OpType = 374 + OpStructFieldOmitEmptyStringPtr OpType = 375 + OpStructFieldStringTagStringPtr OpType = 376 + OpStructEndStringPtr OpType = 377 + OpStructEndOmitEmptyStringPtr OpType = 378 + OpStructEndStringTagStringPtr OpType = 379 + OpStructFieldBytesPtr OpType = 380 + OpStructFieldOmitEmptyBytesPtr OpType = 381 + OpStructFieldStringTagBytesPtr OpType = 382 + OpStructEndBytesPtr OpType = 383 + OpStructEndOmitEmptyBytesPtr OpType = 384 + OpStructEndStringTagBytesPtr OpType = 385 + OpStructFieldNumberPtr OpType = 386 + OpStructFieldOmitEmptyNumberPtr OpType = 387 + OpStructFieldStringTagNumberPtr OpType = 388 + OpStructEndNumberPtr OpType = 389 + OpStructEndOmitEmptyNumberPtr OpType = 390 + OpStructEndStringTagNumberPtr OpType = 391 + OpStructFieldArrayPtr OpType = 392 + OpStructFieldOmitEmptyArrayPtr OpType = 393 + OpStructFieldStringTagArrayPtr OpType = 394 + OpStructEndArrayPtr OpType = 395 + OpStructEndOmitEmptyArrayPtr OpType = 396 + OpStructEndStringTagArrayPtr OpType = 397 + OpStructFieldMapPtr OpType = 398 + OpStructFieldOmitEmptyMapPtr OpType = 399 + OpStructFieldStringTagMapPtr OpType = 400 + OpStructEndMapPtr OpType = 401 + OpStructEndOmitEmptyMapPtr OpType = 402 + OpStructEndStringTagMapPtr OpType = 403 + OpStructFieldSlicePtr OpType = 404 + OpStructFieldOmitEmptySlicePtr OpType = 405 + OpStructFieldStringTagSlicePtr OpType = 406 + OpStructEndSlicePtr OpType = 407 + OpStructEndOmitEmptySlicePtr OpType = 408 + OpStructEndStringTagSlicePtr OpType = 409 + OpStructFieldMarshalJSONPtr OpType = 410 + OpStructFieldOmitEmptyMarshalJSONPtr OpType = 411 + OpStructFieldStringTagMarshalJSONPtr OpType = 412 + OpStructEndMarshalJSONPtr OpType = 413 + OpStructEndOmitEmptyMarshalJSONPtr OpType = 414 + OpStructEndStringTagMarshalJSONPtr OpType = 415 + OpStructFieldMarshalTextPtr OpType = 416 + OpStructFieldOmitEmptyMarshalTextPtr OpType = 417 + OpStructFieldStringTagMarshalTextPtr OpType = 418 + OpStructEndMarshalTextPtr OpType = 419 + OpStructEndOmitEmptyMarshalTextPtr OpType = 420 + OpStructEndStringTagMarshalTextPtr OpType = 421 + OpStructFieldInterfacePtr OpType = 422 + OpStructFieldOmitEmptyInterfacePtr OpType = 423 + OpStructFieldStringTagInterfacePtr OpType = 424 + OpStructEndInterfacePtr OpType = 425 + OpStructEndOmitEmptyInterfacePtr OpType = 426 + OpStructEndStringTagInterfacePtr OpType = 427 + OpStructFieldRecursivePtr OpType = 428 + OpStructFieldOmitEmptyRecursivePtr OpType = 429 + OpStructFieldStringTagRecursivePtr OpType = 430 + OpStructEndRecursivePtr OpType = 431 + OpStructEndOmitEmptyRecursivePtr OpType = 432 + OpStructEndStringTagRecursivePtr OpType = 433 + OpStructField OpType = 434 + OpStructFieldOmitEmpty OpType = 435 + OpStructFieldStringTag OpType = 436 + OpStructEnd OpType = 437 + OpStructEndOmitEmpty OpType = 438 + OpStructEndStringTag OpType = 439 +) + +func (t OpType) String() string { + if int(t) >= 440 { + return "" + } + return opTypeStrings[int(t)] +} + +func (t OpType) CodeType() CodeType { + if strings.Contains(t.String(), "Struct") { + if strings.Contains(t.String(), "End") { + return CodeStructEnd + } + return CodeStructField + } + switch t { + case OpArray, OpArrayPtr: + return CodeArrayHead + case OpArrayElem: + return CodeArrayElem + case OpSlice, OpSlicePtr: + return CodeSliceHead + case OpSliceElem: + return CodeSliceElem + case OpMap, OpMapPtr: + return CodeMapHead + case OpMapKey: + return CodeMapKey + case OpMapValue: + return CodeMapValue + case OpMapEnd: + return CodeMapEnd + } + + return CodeOp +} + +func (t OpType) HeadToPtrHead() OpType { + if strings.Index(t.String(), "PtrHead") > 0 { + return t + } + + idx := strings.Index(t.String(), "Head") + if idx == -1 { + return t + } + suffix := "Ptr" + t.String()[idx+len("Head"):] + + const toPtrOffset = 3 + if strings.Contains(OpType(int(t)+toPtrOffset).String(), suffix) { + return OpType(int(t) + toPtrOffset) + } + return t +} + +func (t OpType) HeadToOmitEmptyHead() OpType { + const toOmitEmptyOffset = 1 + if strings.Contains(OpType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) + } + + return t +} + +func (t OpType) HeadToStringTagHead() OpType { + const toStringTagOffset = 2 + if strings.Contains(OpType(int(t)+toStringTagOffset).String(), "StringTag") { + return OpType(int(t) + toStringTagOffset) + } + return t +} + +func (t OpType) PtrHeadToHead() OpType { + idx := strings.Index(t.String(), "Ptr") + if idx == -1 { + return t + } + suffix := t.String()[idx+len("Ptr"):] + + const toPtrOffset = 3 + if strings.Contains(OpType(int(t)-toPtrOffset).String(), suffix) { + return OpType(int(t) - toPtrOffset) + } + return t +} + +func (t OpType) FieldToEnd() OpType { + idx := strings.Index(t.String(), "Field") + if idx == -1 { + return t + } + suffix := t.String()[idx+len("Field"):] + const toEndOffset = 3 + if strings.Contains(OpType(int(t)+toEndOffset).String(), "End"+suffix) { + return OpType(int(t) + toEndOffset) + } + return t +} + +func (t OpType) FieldToOmitEmptyField() OpType { + const toOmitEmptyOffset = 1 + if strings.Contains(OpType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) + } + return t +} + +func (t OpType) FieldToStringTagField() OpType { + const toStringTagOffset = 2 + if strings.Contains(OpType(int(t)+toStringTagOffset).String(), "StringTag") { + return OpType(int(t) + toStringTagOffset) + } + return t +} diff --git a/internal/encoder/string.go b/internal/encoder/string.go new file mode 100644 index 0000000..26da31a --- /dev/null +++ b/internal/encoder/string.go @@ -0,0 +1,637 @@ +package encoder + +import ( + "math/bits" + "reflect" + "unicode/utf8" + "unsafe" +) + +const ( + lsb = 0x0101010101010101 + msb = 0x8080808080808080 +) + +var needEscapeWithHTML = [256]bool{ + '"': true, + '&': true, + '<': true, + '>': true, + '\\': true, + 0x00: true, + 0x01: true, + 0x02: true, + 0x03: true, + 0x04: true, + 0x05: true, + 0x06: true, + 0x07: true, + 0x08: true, + 0x09: true, + 0x0a: true, + 0x0b: true, + 0x0c: true, + 0x0d: true, + 0x0e: true, + 0x0f: true, + 0x10: true, + 0x11: true, + 0x12: true, + 0x13: true, + 0x14: true, + 0x15: true, + 0x16: true, + 0x17: true, + 0x18: true, + 0x19: true, + 0x1a: true, + 0x1b: true, + 0x1c: true, + 0x1d: true, + 0x1e: true, + 0x1f: true, + /* 0x20 - 0x7f */ + 0x80: true, + 0x81: true, + 0x82: true, + 0x83: true, + 0x84: true, + 0x85: true, + 0x86: true, + 0x87: true, + 0x88: true, + 0x89: true, + 0x8a: true, + 0x8b: true, + 0x8c: true, + 0x8d: true, + 0x8e: true, + 0x8f: true, + 0x90: true, + 0x91: true, + 0x92: true, + 0x93: true, + 0x94: true, + 0x95: true, + 0x96: true, + 0x97: true, + 0x98: true, + 0x99: true, + 0x9a: true, + 0x9b: true, + 0x9c: true, + 0x9d: true, + 0x9e: true, + 0x9f: true, + 0xa0: true, + 0xa1: true, + 0xa2: true, + 0xa3: true, + 0xa4: true, + 0xa5: true, + 0xa6: true, + 0xa7: true, + 0xa8: true, + 0xa9: true, + 0xaa: true, + 0xab: true, + 0xac: true, + 0xad: true, + 0xae: true, + 0xaf: true, + 0xb0: true, + 0xb1: true, + 0xb2: true, + 0xb3: true, + 0xb4: true, + 0xb5: true, + 0xb6: true, + 0xb7: true, + 0xb8: true, + 0xb9: true, + 0xba: true, + 0xbb: true, + 0xbc: true, + 0xbd: true, + 0xbe: true, + 0xbf: true, + 0xc0: true, + 0xc1: true, + 0xc2: true, + 0xc3: true, + 0xc4: true, + 0xc5: true, + 0xc6: true, + 0xc7: true, + 0xc8: true, + 0xc9: true, + 0xca: true, + 0xcb: true, + 0xcc: true, + 0xcd: true, + 0xce: true, + 0xcf: true, + 0xd0: true, + 0xd1: true, + 0xd2: true, + 0xd3: true, + 0xd4: true, + 0xd5: true, + 0xd6: true, + 0xd7: true, + 0xd8: true, + 0xd9: true, + 0xda: true, + 0xdb: true, + 0xdc: true, + 0xdd: true, + 0xde: true, + 0xdf: true, + 0xe0: true, + 0xe1: true, + 0xe2: true, + 0xe3: true, + 0xe4: true, + 0xe5: true, + 0xe6: true, + 0xe7: true, + 0xe8: true, + 0xe9: true, + 0xea: true, + 0xeb: true, + 0xec: true, + 0xed: true, + 0xee: true, + 0xef: true, + 0xf0: true, + 0xf1: true, + 0xf2: true, + 0xf3: true, + 0xf4: true, + 0xf5: true, + 0xf6: true, + 0xf7: true, + 0xf8: true, + 0xf9: true, + 0xfa: true, + 0xfb: true, + 0xfc: true, + 0xfd: true, + 0xfe: true, + 0xff: true, +} + +var needEscape = [256]bool{ + '"': true, + '\\': true, + 0x00: true, + 0x01: true, + 0x02: true, + 0x03: true, + 0x04: true, + 0x05: true, + 0x06: true, + 0x07: true, + 0x08: true, + 0x09: true, + 0x0a: true, + 0x0b: true, + 0x0c: true, + 0x0d: true, + 0x0e: true, + 0x0f: true, + 0x10: true, + 0x11: true, + 0x12: true, + 0x13: true, + 0x14: true, + 0x15: true, + 0x16: true, + 0x17: true, + 0x18: true, + 0x19: true, + 0x1a: true, + 0x1b: true, + 0x1c: true, + 0x1d: true, + 0x1e: true, + 0x1f: true, + /* 0x20 - 0x7f */ + 0x80: true, + 0x81: true, + 0x82: true, + 0x83: true, + 0x84: true, + 0x85: true, + 0x86: true, + 0x87: true, + 0x88: true, + 0x89: true, + 0x8a: true, + 0x8b: true, + 0x8c: true, + 0x8d: true, + 0x8e: true, + 0x8f: true, + 0x90: true, + 0x91: true, + 0x92: true, + 0x93: true, + 0x94: true, + 0x95: true, + 0x96: true, + 0x97: true, + 0x98: true, + 0x99: true, + 0x9a: true, + 0x9b: true, + 0x9c: true, + 0x9d: true, + 0x9e: true, + 0x9f: true, + 0xa0: true, + 0xa1: true, + 0xa2: true, + 0xa3: true, + 0xa4: true, + 0xa5: true, + 0xa6: true, + 0xa7: true, + 0xa8: true, + 0xa9: true, + 0xaa: true, + 0xab: true, + 0xac: true, + 0xad: true, + 0xae: true, + 0xaf: true, + 0xb0: true, + 0xb1: true, + 0xb2: true, + 0xb3: true, + 0xb4: true, + 0xb5: true, + 0xb6: true, + 0xb7: true, + 0xb8: true, + 0xb9: true, + 0xba: true, + 0xbb: true, + 0xbc: true, + 0xbd: true, + 0xbe: true, + 0xbf: true, + 0xc0: true, + 0xc1: true, + 0xc2: true, + 0xc3: true, + 0xc4: true, + 0xc5: true, + 0xc6: true, + 0xc7: true, + 0xc8: true, + 0xc9: true, + 0xca: true, + 0xcb: true, + 0xcc: true, + 0xcd: true, + 0xce: true, + 0xcf: true, + 0xd0: true, + 0xd1: true, + 0xd2: true, + 0xd3: true, + 0xd4: true, + 0xd5: true, + 0xd6: true, + 0xd7: true, + 0xd8: true, + 0xd9: true, + 0xda: true, + 0xdb: true, + 0xdc: true, + 0xdd: true, + 0xde: true, + 0xdf: true, + 0xe0: true, + 0xe1: true, + 0xe2: true, + 0xe3: true, + 0xe4: true, + 0xe5: true, + 0xe6: true, + 0xe7: true, + 0xe8: true, + 0xe9: true, + 0xea: true, + 0xeb: true, + 0xec: true, + 0xed: true, + 0xee: true, + 0xef: true, + 0xf0: true, + 0xf1: true, + 0xf2: true, + 0xf3: true, + 0xf4: true, + 0xf5: true, + 0xf6: true, + 0xf7: true, + 0xf8: true, + 0xf9: true, + 0xfa: true, + 0xfb: true, + 0xfc: true, + 0xfd: true, + 0xfe: true, + 0xff: true, +} + +var hex = "0123456789abcdef" + +// escapeIndex finds the index of the first char in `s` that requires escaping. +// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if +// it includes a double quote or backslash. +// If no chars in `s` require escaping, the return value is -1. +func escapeIndex(s string) int { + chunks := stringToUint64Slice(s) + for _, n := range chunks { + // combine masks before checking for the MSB of each byte. We include + // `n` in the mask to check whether any of the *input* byte MSBs were + // set (i.e. the byte was outside the ASCII range). + mask := n | below(n, 0x20) | contains(n, '"') | contains(n, '\\') + if (mask & msb) != 0 { + return bits.TrailingZeros64(mask&msb) / 8 + } + } + + valLen := len(s) + for i := len(chunks) * 8; i < valLen; i++ { + if needEscape[s[i]] { + return i + } + } + + return -1 +} + +// below return a mask that can be used to determine if any of the bytes +// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was +// below `b`. The result is only valid if `b`, and each byte in `n`, is below +// 0x80. +func below(n uint64, b byte) uint64 { + return n - expand(b) +} + +// contains returns a mask that can be used to determine if any of the +// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then +// that byte is equal to `b`. The result is only valid if `b`, and each +// byte in `n`, is below 0x80. +func contains(n uint64, b byte) uint64 { + return (n ^ expand(b)) - lsb +} + +// expand puts the specified byte into each of the 8 bytes of a uint64. +func expand(b byte) uint64 { + return lsb * uint64(b) +} + +//nolint:govet +func stringToUint64Slice(s string) []uint64 { + return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{ + Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data, + Len: len(s) / 8, + Cap: len(s) / 8, + })) +} + +func AppendEscapedString(buf []byte, s string) []byte { + valLen := len(s) + if valLen == 0 { + return append(buf, `""`...) + } + buf = append(buf, '"') + var ( + i, j int + ) + if valLen >= 8 { + chunks := stringToUint64Slice(s) + for _, n := range chunks { + // combine masks before checking for the MSB of each byte. We include + // `n` in the mask to check whether any of the *input* byte MSBs were + // set (i.e. the byte was outside the ASCII range). + mask := n | (n - (lsb * 0x20)) | + ((n ^ (lsb * '"')) - lsb) | + ((n ^ (lsb * '\\')) - lsb) | + ((n ^ (lsb * '<')) - lsb) | + ((n ^ (lsb * '>')) - lsb) | + ((n ^ (lsb * '&')) - lsb) + if (mask & msb) != 0 { + j = bits.TrailingZeros64(mask&msb) / 8 + goto ESCAPE_END + } + } + for i := len(chunks) * 8; i < valLen; i++ { + if needEscapeWithHTML[s[i]] { + j = i + goto ESCAPE_END + } + } + // no found any escape characters. + return append(append(buf, s...), '"') + } +ESCAPE_END: + for j < valLen { + c := s[j] + + if !needEscapeWithHTML[c] { + // fast path: most of the time, printable ascii characters are used + j++ + continue + } + + switch c { + case '\\', '"': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', c) + i = j + 1 + j = j + 1 + continue + + case '\n': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'n') + i = j + 1 + j = j + 1 + continue + + case '\r': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'r') + i = j + 1 + j = j + 1 + continue + + case '\t': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 't') + i = j + 1 + j = j + 1 + continue + + case '<', '>', '&': + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + // This encodes bytes < 0x20 except for \t, \n and \r. + if c < 0x20 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + r, size := utf8.DecodeRuneInString(s[j:]) + + if r == utf8.RuneError && size == 1 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\ufffd`...) + i = j + size + j = j + size + continue + } + + switch r { + case '\u2028', '\u2029': + // U+2028 is LINE SEPARATOR. + // U+2029 is PARAGRAPH SEPARATOR. + // They are both technically valid characters in JSON strings, + // but don't work in JSONP, which has to be evaluated as JavaScript, + // and can lead to security holes there. It is valid JSON to + // escape them, so we do so unconditionally. + // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. + buf = append(buf, s[i:j]...) + buf = append(buf, `\u202`...) + buf = append(buf, hex[r&0xF]) + i = j + size + j = j + size + continue + } + + j += size + } + + return append(append(buf, s[i:]...), '"') +} + +func AppendString(buf []byte, s string) []byte { + valLen := len(s) + if valLen == 0 { + return append(buf, `""`...) + } + buf = append(buf, '"') + var escapeIdx int + if valLen >= 8 { + if escapeIdx = escapeIndex(s); escapeIdx < 0 { + return append(append(buf, s...), '"') + } + } + + i := 0 + j := escapeIdx + for j < valLen { + c := s[j] + + if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' { + // fast path: most of the time, printable ascii characters are used + j++ + continue + } + + switch c { + case '\\', '"': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', c) + i = j + 1 + j = j + 1 + continue + + case '\n': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'n') + i = j + 1 + j = j + 1 + continue + + case '\r': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'r') + i = j + 1 + j = j + 1 + continue + + case '\t': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 't') + i = j + 1 + j = j + 1 + continue + + case '<', '>', '&': + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + // This encodes bytes < 0x20 except for \t, \n and \r. + if c < 0x20 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + r, size := utf8.DecodeRuneInString(s[j:]) + + if r == utf8.RuneError && size == 1 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\ufffd`...) + i = j + size + j = j + size + continue + } + + switch r { + case '\u2028', '\u2029': + // U+2028 is LINE SEPARATOR. + // U+2029 is PARAGRAPH SEPARATOR. + // They are both technically valid characters in JSON strings, + // but don't work in JSONP, which has to be evaluated as JavaScript, + // and can lead to security holes there. It is valid JSON to + // escape them, so we do so unconditionally. + // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. + buf = append(buf, s[i:j]...) + buf = append(buf, `\u202`...) + buf = append(buf, hex[r&0xF]) + i = j + size + j = j + size + continue + } + + j += size + } + + return append(append(buf, s[i:]...), '"') +} diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go new file mode 100644 index 0000000..e7fddd4 --- /dev/null +++ b/internal/encoder/vm/vm.go @@ -0,0 +1,3759 @@ +package json + +import ( + "fmt" + "math" + "reflect" + "sort" + "strings" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/encoder/compiler" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const + +var ( + load = encoder.Load + store = encoder.Store + loadAndStoreNPtr = encoder.LoadAndStoreNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSON + appendMarshalText = encoder.AppendMarshalText + appendNull = encoder.AppendNull + appendComma = encoder.AppendComma + appendStructEnd = encoder.AppendStructEnd + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + errMarshalerWithCode = encoder.ErrMarshalerWithCode + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + code := codeSet.Code + + for { + switch code.Op { + default: + return nil, fmt.Errorf("encoder: opcode %s has not been implemented", code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpInt: + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpUintPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpUint: + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpFloat32Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpFloat64Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, encoder.ErrUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStringPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpString: + b = appendString(b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBoolPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpBool: + b = appendBool(b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBytesPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpNumberPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpInterfacePtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := compiler.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(codeSet.CodeLength) + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + oldPtrs := ctx.Ptrs + + newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] + newPtrs[0] = uintptr(iface.ptr) + + ctx.Ptrs = newPtrs + + bb, err := Run(ctx, b, ifaceCodeSet, opt) + if err != nil { + return nil, err + } + + ctx.Ptrs = oldPtrs + ctxptr = ctx.Ptr() + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + b = bb + code = code.Next + case encoder.OpMarshalJSONPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpMarshalTextPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpSlicePtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + if slice.Len > 0 { + b = append(b, '[') + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = append(b, '[', ']', ',') + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + last := len(b) - 1 + b[last] = ']' + b = appendComma(b) + code = code.End.Next + } + case encoder.OpArrayPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + if code.Length > 0 { + b = append(b, '[') + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = append(b, '[', ']', ',') + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < code.Length { + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + last := len(b) - 1 + b[last] = ']' + b = appendComma(b) + code = code.End.Next + } + case encoder.OpMapPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = append(b, '{', '}', ',') + code = code.End.Next + break + } + b = append(b, '{') + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (opt & encoder.UnorderedMapOption) == 0 { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (opt & encoder.UnorderedMapOption) != 0 { + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + last := len(b) - 1 + b[last] = '}' + b = appendComma(b) + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (opt & encoder.UnorderedMapOption) != 0 { + last := len(b) - 1 + b[last] = ':' + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = append(buf, item.Key...) + buf[len(buf)-1] = ':' + buf = append(buf, item.Value...) + } + buf[len(buf)-1] = '}' + buf = append(buf, ',') + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpStructFieldRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructFieldRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + code = c + recursiveLevel++ + case encoder.OpStructFieldRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if !code.AnonymousKey { + b = append(b, code.Key...) + } + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + if p == 0 || (ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr")) { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadStringTag: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTag: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadInt: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendInt(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagInt: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadIntPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagIntPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUint: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendUint(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagUint: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUintPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagUintPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat32(p + code.Offset) + if v == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendFloat32(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat32: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat32Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat64(p + code.Offset) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat64: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat64Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadString: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToString(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendString(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagString: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagStringPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBool: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.Key...) + b = appendBool(b, v) + b = appendComma(b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadStringTagBool: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBoolPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBoolPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytes: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToBytes(p + code.Offset) + if v == nil { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagBytes: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytesPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBytesPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumber: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToNumber(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagNumber: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumberPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagNumberPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadStringTagArray, + encoder.OpStructPtrHeadSlice, encoder.OpStructPtrHeadStringTagSlice: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadStringTagArray, + encoder.OpStructHeadSlice, encoder.OpStructHeadStringTagSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + slice := ptrToSlice(p) + if slice.Data == nil { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadStringTagArrayPtr, + encoder.OpStructPtrHeadSlicePtr, encoder.OpStructPtrHeadStringTagSlicePtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadStringTagArrayPtr, + encoder.OpStructHeadSlicePtr, encoder.OpStructHeadStringTagSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap, encoder.OpStructPtrHeadStringTagMap: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMap, encoder.OpStructHeadStringTagMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr, encoder.OpStructPtrHeadStringTagMapPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMapPtr, encoder.OpStructHeadStringTagMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalJSON: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr, encoder.OpStructPtrHeadStringTagMarshalJSONPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr, encoder.OpStructHeadStringTagMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalText: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr, encoder.OpStructPtrHeadStringTagMarshalTextPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMarshalTextPtr, encoder.OpStructHeadStringTagMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructField: + if !code.AnonymousKey { + b = append(b, code.Key...) + } + p := load(ctxptr, code.HeadIdx) + code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr") { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldStringTag: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.Key...) + b = appendInt(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldIntPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.Key...) + b = appendUint(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUintPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = append(b, code.Key...) + b = appendString(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldStringPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagStringPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.Key...) + b = appendBool(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBoolPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBoolPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytes: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + b = append(b, code.Key...) + b = appendByteSlice(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytesPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytesPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = append(b, code.Key...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumberPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumberPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldMarshalJSON, encoder.OpStructFieldStringTagMarshalJSON: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = append(b, code.Key...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr, encoder.OpStructFieldStringTagMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText, encoder.OpStructFieldStringTagMarshalText: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = append(b, code.Key...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr, encoder.OpStructFieldStringTagMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldArray, encoder.OpStructFieldStringTagArray: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr, encoder.OpStructFieldStringTagArrayPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice, encoder.OpStructFieldStringTagSlice: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr, encoder.OpStructFieldStringTagSlicePtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap, encoder.OpStructFieldStringTagMap: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr, encoder.OpStructFieldStringTagMapPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructEnd: + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + } else { + b = append(b, '}') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEndInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.Key...) + b = appendInt(b, u64, code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndIntPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p), code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagIntPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.Key...) + b = appendUint(b, u64, code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndUintPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p), code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagUintPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat32Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat64: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = appendFloat64(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendStructEnd(b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat64Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = append(b, code.Key...) + b = appendString(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndStringPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendString(b, ptrToString(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagStringPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToString(p) + b = appendString(b, string(appendString([]byte{}, v))) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.Key...) + b = appendBool(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBoolPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBoolPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBytes: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + b = append(b, code.Key...) + b = appendByteSlice(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBytesPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBytesPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = append(b, code.Key...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndNumberPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagNumberPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} diff --git a/internal/runtime/type.go b/internal/runtime/type.go new file mode 100644 index 0000000..fd425f7 --- /dev/null +++ b/internal/runtime/type.go @@ -0,0 +1,9 @@ +package runtime + +import "unsafe" + +type SliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +} From 62b7d3ba0a98e3d11e7520bf802a9df647f78ac0 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 16 Mar 2021 19:44:32 +0900 Subject: [PATCH 04/15] Move compiler for encoder to internal package --- internal/encoder/compiler.go | 1210 +++++++++++++++++++++++++ internal/encoder/compiler/compiler.go | 1 - internal/encoder/compiler/norace.go | 11 - internal/encoder/compiler_norace.go | 38 + internal/encoder/compiler_race.go | 46 + internal/encoder/context.go | 82 ++ internal/encoder/encoder.go | 135 ++- internal/encoder/opcode.go | 647 +++++++++++++ internal/encoder/vm/vm.go | 5 +- internal/runtime/struct_field.go | 81 ++ internal/runtime/type.go | 80 +- 11 files changed, 2286 insertions(+), 50 deletions(-) create mode 100644 internal/encoder/compiler.go delete mode 100644 internal/encoder/compiler/compiler.go delete mode 100644 internal/encoder/compiler/norace.go create mode 100644 internal/encoder/compiler_norace.go create mode 100644 internal/encoder/compiler_race.go create mode 100644 internal/encoder/context.go create mode 100644 internal/encoder/opcode.go create mode 100644 internal/runtime/struct_field.go diff --git a/internal/encoder/compiler.go b/internal/encoder/compiler.go new file mode 100644 index 0000000..aa8d066 --- /dev/null +++ b/internal/encoder/compiler.go @@ -0,0 +1,1210 @@ +package encoder + +import ( + "encoding" + "encoding/json" + "fmt" + "reflect" + "strings" + "sync/atomic" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +var ( + marshalJSONType = reflect.TypeOf((*json.Marshaler)(nil)).Elem() + marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() + jsonNumberType = reflect.TypeOf(json.Number("")) + cachedOpcodeSets []*OpcodeSet + cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet + typeAddr = &runtime.TypeAddr{} +) + +func init() { + typeAddr = runtime.AnalyzeTypeAddr() + cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange) +} + +func loadOpcodeMap() map[uintptr]*OpcodeSet { + p := atomic.LoadPointer(&cachedOpcodeMap) + return *(*map[uintptr]*OpcodeSet)(unsafe.Pointer(&p)) +} + +func storeOpcodeSet(typ uintptr, set *OpcodeSet, m map[uintptr]*OpcodeSet) { + newOpcodeMap := make(map[uintptr]*OpcodeSet, len(m)+1) + newOpcodeMap[typ] = set + + for k, v := range m { + newOpcodeMap[k] = v + } + + atomic.StorePointer(&cachedOpcodeMap, *(*unsafe.Pointer)(unsafe.Pointer(&newOpcodeMap))) +} + +func compileToGetCodeSetSlowPath(typeptr uintptr) (*OpcodeSet, error) { + opcodeMap := loadOpcodeMap() + if codeSet, exists := opcodeMap[typeptr]; exists { + return codeSet, nil + } + + // noescape trick for header.typ ( reflect.*rtype ) + copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr)) + + code, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + }) + if err != nil { + return nil, err + } + code = copyOpcode(code) + codeLength := code.TotalLength() + codeSet := &OpcodeSet{ + Code: code, + CodeLength: codeLength, + } + storeOpcodeSet(typeptr, codeSet, opcodeMap) + return codeSet, nil +} + +func compileHead(ctx *compileContext) (*Opcode, error) { + typ := ctx.typ + switch { + case implementsMarshalJSON(typ): + return compileMarshalJSON(ctx) + case implementsMarshalText(typ): + return compileMarshalText(ctx) + } + + isPtr := false + orgType := typ + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + isPtr = true + } + switch { + case implementsMarshalJSON(typ): + return compileMarshalJSON(ctx) + case implementsMarshalText(typ): + return compileMarshalText(ctx) + } + if typ.Kind() == reflect.Map { + if isPtr { + return compilePtr(ctx.withType(runtime.PtrTo(typ))) + } + return compileMap(ctx.withType(typ)) + } else if typ.Kind() == reflect.Struct { + code, err := compileStruct(ctx.withType(typ), isPtr) + if err != nil { + return nil, err + } + optimizeStructEnd(code) + linkRecursiveCode(code) + return code, nil + } else if isPtr && typ.Implements(marshalTextType) { + typ = orgType + } + code, err := compile(ctx.withType(typ), isPtr) + if err != nil { + return nil, err + } + optimizeStructEnd(code) + linkRecursiveCode(code) + return code, nil +} + +func linkRecursiveCode(c *Opcode) { + for code := c; code.Op != OpEnd && code.Op != OpStructFieldRecursiveEnd; { + switch code.Op { + case OpStructFieldRecursive, OpStructFieldRecursivePtr: + if code.Jmp.Linked { + code = code.Next + continue + } + code.Jmp.Code = copyOpcode(code.Jmp.Code) + c := code.Jmp.Code + c.End.Next = newEndOp(&compileContext{}) + c.Op = c.Op.PtrHeadToHead() + + beforeLastCode := c.End + lastCode := beforeLastCode.Next + + lastCode.Idx = beforeLastCode.Idx + uintptrSize + lastCode.ElemIdx = lastCode.Idx + uintptrSize + + // extend length to alloc slot for elemIdx + totalLength := uintptr(code.TotalLength() + 1) + nextTotalLength := uintptr(c.TotalLength() + 1) + + c.End.Next.Op = OpStructFieldRecursiveEnd + + code.Jmp.CurLen = totalLength + code.Jmp.NextLen = nextTotalLength + code.Jmp.Linked = true + + linkRecursiveCode(code.Jmp.Code) + code = code.Next + continue + } + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } +} + +func optimizeStructEnd(c *Opcode) { + for code := c; code.Op != OpEnd; { + if code.Op == OpStructFieldRecursive || code.Op == OpStructFieldRecursivePtr { + // ignore if exists recursive operation + return + } + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } + + for code := c; code.Op != OpEnd; { + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + case CodeStructEnd: + switch code.Op { + case OpStructEnd: + prev := code.PrevField + prevOp := prev.Op.String() + if strings.Contains(prevOp, "Head") || + strings.Contains(prevOp, "Slice") || + strings.Contains(prevOp, "Array") || + strings.Contains(prevOp, "Map") || + strings.Contains(prevOp, "MarshalJSON") || + strings.Contains(prevOp, "MarshalText") { + // not exists field + code = code.Next + break + } + if prev.Op != prev.Op.FieldToEnd() { + prev.Op = prev.Op.FieldToEnd() + prev.Next = code.Next + } + code = code.Next + default: + code = code.Next + } + default: + code = code.Next + } + } +} + +func implementsMarshalJSON(typ *runtime.Type) bool { + if !typ.Implements(marshalJSONType) { + return false + } + if typ.Kind() != reflect.Ptr { + return true + } + // type kind is reflect.Ptr + if !typ.Elem().Implements(marshalJSONType) { + return true + } + // needs to dereference + return false +} + +func implementsMarshalText(typ *runtime.Type) bool { + if !typ.Implements(marshalTextType) { + return false + } + if typ.Kind() != reflect.Ptr { + return true + } + // type kind is reflect.Ptr + if !typ.Elem().Implements(marshalTextType) { + return true + } + // needs to dereference + return false +} + +func compile(ctx *compileContext, isPtr bool) (*Opcode, error) { + typ := ctx.typ + switch { + case implementsMarshalJSON(typ): + return compileMarshalJSON(ctx) + case implementsMarshalText(typ): + return compileMarshalText(ctx) + } + switch typ.Kind() { + case reflect.Ptr: + return compilePtr(ctx) + case reflect.Slice: + elem := typ.Elem() + if elem.Kind() == reflect.Uint8 { + p := runtime.PtrTo(elem) + if !p.Implements(marshalJSONType) && !p.Implements(marshalTextType) { + return compileBytes(ctx) + } + } + return compileSlice(ctx) + case reflect.Array: + return compileArray(ctx) + case reflect.Map: + return compileMap(ctx) + case reflect.Struct: + return compileStruct(ctx, isPtr) + case reflect.Interface: + return compileInterface(ctx) + case reflect.Int: + return compileInt(ctx) + case reflect.Int8: + return compileInt8(ctx) + case reflect.Int16: + return compileInt16(ctx) + case reflect.Int32: + return compileInt32(ctx) + case reflect.Int64: + return compileInt64(ctx) + case reflect.Uint: + return compileUint(ctx) + case reflect.Uint8: + return compileUint8(ctx) + case reflect.Uint16: + return compileUint16(ctx) + case reflect.Uint32: + return compileUint32(ctx) + case reflect.Uint64: + return compileUint64(ctx) + case reflect.Uintptr: + return compileUint(ctx) + case reflect.Float32: + return compileFloat32(ctx) + case reflect.Float64: + return compileFloat64(ctx) + case reflect.String: + return compileString(ctx) + case reflect.Bool: + return compileBool(ctx) + } + return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)} +} + +func convertPtrOp(code *Opcode) OpType { + ptrHeadOp := code.Op.HeadToPtrHead() + if code.Op != ptrHeadOp { + return ptrHeadOp + } + switch code.Op { + case OpInt: + return OpIntPtr + case OpUint: + return OpUintPtr + case OpFloat32: + return OpFloat32Ptr + case OpFloat64: + return OpFloat64Ptr + case OpString: + return OpStringPtr + case OpBool: + return OpBoolPtr + case OpBytes: + return OpBytesPtr + case OpArray: + return OpArrayPtr + case OpSlice: + return OpSlicePtr + case OpMap: + return OpMapPtr + case OpMarshalJSON: + return OpMarshalJSONPtr + case OpMarshalText: + return OpMarshalTextPtr + case OpInterface: + return OpInterfacePtr + case OpStructFieldRecursive: + return OpStructFieldRecursivePtr + } + return code.Op +} + +func compileKey(ctx *compileContext) (*Opcode, error) { + typ := ctx.typ + switch { + case implementsMarshalJSON(typ): + return compileMarshalJSON(ctx) + case implementsMarshalText(typ): + return compileMarshalText(ctx) + } + switch typ.Kind() { + case reflect.Ptr: + return compilePtr(ctx) + case reflect.Interface: + return compileInterface(ctx) + case reflect.String: + return compileString(ctx) + case reflect.Int: + return compileIntString(ctx) + case reflect.Int8: + return compileInt8String(ctx) + case reflect.Int16: + return compileInt16String(ctx) + case reflect.Int32: + return compileInt32String(ctx) + case reflect.Int64: + return compileInt64String(ctx) + case reflect.Uint: + return compileUintString(ctx) + case reflect.Uint8: + return compileUint8String(ctx) + case reflect.Uint16: + return compileUint16String(ctx) + case reflect.Uint32: + return compileUint32String(ctx) + case reflect.Uint64: + return compileUint64String(ctx) + case reflect.Uintptr: + return compileUintString(ctx) + } + return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)} +} + +func compilePtr(ctx *compileContext) (*Opcode, error) { + code, err := compile(ctx.withType(ctx.typ.Elem()), true) + if err != nil { + return nil, err + } + code.Op = convertPtrOp(code) + code.PtrNum++ + return code, nil +} + +func compileMarshalJSON(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpMarshalJSON) + typ := ctx.typ + if !typ.Implements(marshalJSONType) && runtime.PtrTo(typ).Implements(marshalJSONType) { + code.AddrForMarshaler = true + } + ctx.incIndex() + return code, nil +} + +func compileMarshalText(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpMarshalText) + typ := ctx.typ + if !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType) { + code.AddrForMarshaler = true + } + ctx.incIndex() + return code, nil +} + +const intSize = 32 << (^uint(0) >> 63) + +func compileInt(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.setMaskAndRshiftNum(intSize) + ctx.incIndex() + return code, nil +} + +func compileInt8(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.setMaskAndRshiftNum(8) + ctx.incIndex() + return code, nil +} + +func compileInt16(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.setMaskAndRshiftNum(16) + ctx.incIndex() + return code, nil +} + +func compileInt32(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.setMaskAndRshiftNum(32) + ctx.incIndex() + return code, nil +} + +func compileInt64(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.setMaskAndRshiftNum(64) + ctx.incIndex() + return code, nil +} + +func compileUint(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.setMaskAndRshiftNum(intSize) + ctx.incIndex() + return code, nil +} + +func compileUint8(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.setMaskAndRshiftNum(8) + ctx.incIndex() + return code, nil +} + +func compileUint16(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.setMaskAndRshiftNum(16) + ctx.incIndex() + return code, nil +} + +func compileUint32(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.setMaskAndRshiftNum(32) + ctx.incIndex() + return code, nil +} + +func compileUint64(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.setMaskAndRshiftNum(64) + ctx.incIndex() + return code, nil +} + +func compileIntString(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.setMaskAndRshiftNum(intSize) + ctx.incIndex() + return code, nil +} + +func compileInt8String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.setMaskAndRshiftNum(8) + ctx.incIndex() + return code, nil +} + +func compileInt16String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.setMaskAndRshiftNum(16) + ctx.incIndex() + return code, nil +} + +func compileInt32String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.setMaskAndRshiftNum(32) + ctx.incIndex() + return code, nil +} + +func compileInt64String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.setMaskAndRshiftNum(64) + ctx.incIndex() + return code, nil +} + +func compileUintString(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.setMaskAndRshiftNum(intSize) + ctx.incIndex() + return code, nil +} + +func compileUint8String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.setMaskAndRshiftNum(8) + ctx.incIndex() + return code, nil +} + +func compileUint16String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.setMaskAndRshiftNum(16) + ctx.incIndex() + return code, nil +} + +func compileUint32String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.setMaskAndRshiftNum(32) + ctx.incIndex() + return code, nil +} + +func compileUint64String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.setMaskAndRshiftNum(64) + ctx.incIndex() + return code, nil +} + +func compileFloat32(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpFloat32) + ctx.incIndex() + return code, nil +} + +func compileFloat64(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpFloat64) + ctx.incIndex() + return code, nil +} + +func compileString(ctx *compileContext) (*Opcode, error) { + var op OpType + if ctx.typ == runtime.Type2RType(jsonNumberType) { + op = OpNumber + } else { + op = OpString + } + code := newOpCode(ctx, op) + ctx.incIndex() + return code, nil +} + +func compileBool(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpBool) + ctx.incIndex() + return code, nil +} + +func compileBytes(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpBytes) + ctx.incIndex() + return code, nil +} + +func compileInterface(ctx *compileContext) (*Opcode, error) { + code := newInterfaceCode(ctx) + ctx.incIndex() + return code, nil +} + +func compileSlice(ctx *compileContext) (*Opcode, error) { + elem := ctx.typ.Elem() + size := elem.Size() + + header := newSliceHeaderCode(ctx) + ctx.incIndex() + + code, err := compileSliceElem(ctx.withType(elem).incIndent()) + if err != nil { + return nil, err + } + + // header => opcode => elem => end + // ^ | + // |________| + + elemCode := newSliceElemCode(ctx, header, size) + ctx.incIndex() + + end := newOpCode(ctx, OpSliceEnd) + ctx.incIndex() + + header.Elem = elemCode + header.End = end + header.Next = code + code.BeforeLastCode().Next = (*Opcode)(unsafe.Pointer(elemCode)) + elemCode.Next = code + elemCode.End = end + return (*Opcode)(unsafe.Pointer(header)), nil +} + +func compileSliceElem(ctx *compileContext) (*Opcode, error) { + typ := ctx.typ + switch { + case !typ.Implements(marshalJSONType) && runtime.PtrTo(typ).Implements(marshalJSONType): + return compileMarshalJSON(ctx) + case !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType): + return compileMarshalText(ctx) + default: + return compile(ctx, false) + } +} + +func compileArray(ctx *compileContext) (*Opcode, error) { + typ := ctx.typ + elem := typ.Elem() + alen := typ.Len() + size := elem.Size() + + header := newArrayHeaderCode(ctx, alen) + ctx.incIndex() + + code, err := compile(ctx.withType(elem).incIndent(), false) + if err != nil { + return nil, err + } + // header => opcode => elem => end + // ^ | + // |________| + + elemCode := newArrayElemCode(ctx, header, alen, size) + ctx.incIndex() + + end := newOpCode(ctx, OpArrayEnd) + ctx.incIndex() + + header.Elem = elemCode + header.End = end + header.Next = code + code.BeforeLastCode().Next = (*Opcode)(unsafe.Pointer(elemCode)) + elemCode.Next = code + elemCode.End = end + return (*Opcode)(unsafe.Pointer(header)), nil +} + +func compileMap(ctx *compileContext) (*Opcode, error) { + // header => code => value => code => key => code => value => code => end + // ^ | + // |_______________________| + ctx = ctx.incIndent() + header := newMapHeaderCode(ctx) + ctx.incIndex() + + typ := ctx.typ + keyType := ctx.typ.Key() + keyCode, err := compileKey(ctx.withType(keyType)) + if err != nil { + return nil, err + } + + value := newMapValueCode(ctx, header) + ctx.incIndex() + + valueCode, err := compileMapValue(ctx.withType(typ.Elem())) + if err != nil { + return nil, err + } + + key := newMapKeyCode(ctx, header) + ctx.incIndex() + + ctx = ctx.decIndent() + + header.MapKey = key + header.MapValue = value + + end := newMapEndCode(ctx, header) + ctx.incIndex() + + header.Next = keyCode + keyCode.BeforeLastCode().Next = (*Opcode)(unsafe.Pointer(value)) + value.Next = valueCode + valueCode.BeforeLastCode().Next = (*Opcode)(unsafe.Pointer(key)) + key.Next = keyCode + + header.End = end + key.End = end + value.End = end + + return (*Opcode)(unsafe.Pointer(header)), nil +} + +func compileMapValue(ctx *compileContext) (*Opcode, error) { + switch ctx.typ.Kind() { + case reflect.Map: + return compilePtr(ctx.withType(runtime.PtrTo(ctx.typ))) + default: + return compile(ctx, false) + } +} + +func optimizeStructHeader(code *Opcode, tag *runtime.StructTag) OpType { + headType := code.ToHeaderType() + switch { + case tag.IsOmitEmpty: + headType = headType.HeadToOmitEmptyHead() + case tag.IsString: + headType = headType.HeadToStringTagHead() + } + return headType +} + +func optimizeStructField(code *Opcode, tag *runtime.StructTag) OpType { + fieldType := code.ToFieldType() + switch { + case tag.IsOmitEmpty: + fieldType = fieldType.FieldToOmitEmptyField() + case tag.IsString: + fieldType = fieldType.FieldToStringTagField() + } + return fieldType +} + +func recursiveCode(ctx *compileContext, jmp *CompiledCode) *Opcode { + code := newRecursiveCode(ctx, jmp) + ctx.incIndex() + return code +} + +func compiledCode(ctx *compileContext) *Opcode { + typ := ctx.typ + typeptr := uintptr(unsafe.Pointer(typ)) + if cc, exists := ctx.structTypeToCompiledCode[typeptr]; exists { + return recursiveCode(ctx, cc) + } + return nil +} + +func structHeader(ctx *compileContext, fieldCode *Opcode, valueCode *Opcode, tag *runtime.StructTag) *Opcode { + fieldCode.Indent-- + op := optimizeStructHeader(valueCode, tag) + fieldCode.Op = op + fieldCode.Mask = valueCode.Mask + fieldCode.RshiftNum = valueCode.RshiftNum + fieldCode.PtrNum = valueCode.PtrNum + if op.IsMultipleOpHead() { + return valueCode.BeforeLastCode() + } + ctx.decOpcodeIndex() + return (*Opcode)(unsafe.Pointer(fieldCode)) +} + +func structField(ctx *compileContext, fieldCode *Opcode, valueCode *Opcode, tag *runtime.StructTag) *Opcode { + code := (*Opcode)(unsafe.Pointer(fieldCode)) + op := optimizeStructField(valueCode, tag) + fieldCode.Op = op + fieldCode.PtrNum = valueCode.PtrNum + fieldCode.Mask = valueCode.Mask + fieldCode.RshiftNum = valueCode.RshiftNum + fieldCode.Jmp = valueCode.Jmp + if op.IsMultipleOpField() { + return valueCode.BeforeLastCode() + } + ctx.decIndex() + return code +} + +func isNotExistsField(head *Opcode) bool { + if head == nil { + return false + } + if head.Op != OpStructHead { + return false + } + if !head.AnonymousHead { + return false + } + if head.Next == nil { + return false + } + if head.NextField == nil { + return false + } + if head.NextField.Op != OpStructAnonymousEnd { + return false + } + if head.Next.Op == OpStructAnonymousEnd { + return true + } + if head.Next.Op.CodeType() != CodeStructField { + return false + } + return isNotExistsField(head.Next) +} + +func optimizeAnonymousFields(head *Opcode) { + code := head + var prev *Opcode + removedFields := map[*Opcode]struct{}{} + for { + if code.Op == OpStructEnd { + break + } + if code.Op == OpStructField { + codeType := code.Next.Op.CodeType() + if codeType == CodeStructField { + if isNotExistsField(code.Next) { + code.Next = code.NextField + diff := code.Next.DisplayIdx - code.DisplayIdx + for i := 0; i < diff; i++ { + code.Next.decOpcodeIndex() + } + linkPrevToNextField(code, removedFields) + code = prev + } + } + } + prev = code + code = code.NextField + } +} + +type structFieldPair struct { + prevField *Opcode + curField *Opcode + isTaggedKey bool + linked bool +} + +func anonymousStructFieldPairMap(tags runtime.StructTags, named string, valueCode *Opcode) map[string][]structFieldPair { + anonymousFields := map[string][]structFieldPair{} + f := valueCode + var prevAnonymousField *Opcode + removedFields := map[*Opcode]struct{}{} + for { + existsKey := tags.ExistsKey(f.DisplayKey) + isHeadOp := strings.Contains(f.Op.String(), "Head") + if existsKey && strings.Contains(f.Op.String(), "Recursive") { + // through + } else if isHeadOp && !f.AnonymousHead { + if existsKey { + // TODO: need to remove this head + f.Op = OpStructHead + f.AnonymousKey = true + f.AnonymousHead = true + } else if named == "" { + f.AnonymousHead = true + } + } else if named == "" && f.Op == OpStructEnd { + f.Op = OpStructAnonymousEnd + } else if existsKey { + diff := f.NextField.DisplayIdx - f.DisplayIdx + for i := 0; i < diff; i++ { + f.NextField.decOpcodeIndex() + } + linkPrevToNextField(f, removedFields) + } + + if f.DisplayKey == "" { + if f.NextField == nil { + break + } + prevAnonymousField = f + f = f.NextField + continue + } + + key := fmt.Sprintf("%s.%s", named, f.DisplayKey) + anonymousFields[key] = append(anonymousFields[key], structFieldPair{ + prevField: prevAnonymousField, + curField: f, + isTaggedKey: f.IsTaggedKey, + }) + if f.Next != nil && f.NextField != f.Next && f.Next.Op.CodeType() == CodeStructField { + for k, v := range anonymousFieldPairRecursively(named, f.Next) { + anonymousFields[k] = append(anonymousFields[k], v...) + } + } + if f.NextField == nil { + break + } + prevAnonymousField = f + f = f.NextField + } + return anonymousFields +} + +func anonymousFieldPairRecursively(named string, valueCode *Opcode) map[string][]structFieldPair { + anonymousFields := map[string][]structFieldPair{} + f := valueCode + var prevAnonymousField *Opcode + for { + if f.DisplayKey != "" && f.AnonymousHead { + key := fmt.Sprintf("%s.%s", named, f.DisplayKey) + anonymousFields[key] = append(anonymousFields[key], structFieldPair{ + prevField: prevAnonymousField, + curField: f, + isTaggedKey: f.IsTaggedKey, + }) + if f.Next != nil && f.NextField != f.Next && f.Next.Op.CodeType() == CodeStructField { + for k, v := range anonymousFieldPairRecursively(named, f.Next) { + anonymousFields[k] = append(anonymousFields[k], v...) + } + } + } + if f.NextField == nil { + break + } + prevAnonymousField = f + f = f.NextField + } + return anonymousFields +} + +func optimizeConflictAnonymousFields(anonymousFields map[string][]structFieldPair) { + removedFields := map[*Opcode]struct{}{} + for _, fieldPairs := range anonymousFields { + if len(fieldPairs) == 1 { + continue + } + // conflict anonymous fields + taggedPairs := []structFieldPair{} + for _, fieldPair := range fieldPairs { + if fieldPair.isTaggedKey { + taggedPairs = append(taggedPairs, fieldPair) + } else { + if !fieldPair.linked { + if fieldPair.prevField == nil { + // head operation + fieldPair.curField.Op = OpStructHead + fieldPair.curField.AnonymousHead = true + fieldPair.curField.AnonymousKey = true + } else { + diff := fieldPair.curField.NextField.DisplayIdx - fieldPair.curField.DisplayIdx + for i := 0; i < diff; i++ { + fieldPair.curField.NextField.decOpcodeIndex() + } + removedFields[fieldPair.curField] = struct{}{} + linkPrevToNextField(fieldPair.curField, removedFields) + } + fieldPair.linked = true + } + } + } + if len(taggedPairs) > 1 { + for _, fieldPair := range taggedPairs { + if !fieldPair.linked { + if fieldPair.prevField == nil { + // head operation + fieldPair.curField.Op = OpStructHead + fieldPair.curField.AnonymousHead = true + fieldPair.curField.AnonymousKey = true + } else { + diff := fieldPair.curField.NextField.DisplayIdx - fieldPair.curField.DisplayIdx + removedFields[fieldPair.curField] = struct{}{} + for i := 0; i < diff; i++ { + fieldPair.curField.NextField.decOpcodeIndex() + } + linkPrevToNextField(fieldPair.curField, removedFields) + } + fieldPair.linked = true + } + } + } else { + for _, fieldPair := range taggedPairs { + fieldPair.curField.IsTaggedKey = false + } + } + } +} + +func isNilableType(typ *runtime.Type) bool { + switch typ.Kind() { + case reflect.Ptr: + return true + case reflect.Interface: + return true + case reflect.Slice: + return true + case reflect.Map: + return true + default: + return false + } +} + +func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { + if code := compiledCode(ctx); code != nil { + return code, nil + } + typ := ctx.typ + typeptr := uintptr(unsafe.Pointer(typ)) + compiled := &CompiledCode{} + ctx.structTypeToCompiledCode[typeptr] = compiled + // header => code => structField => code => end + // ^ | + // |__________| + fieldNum := typ.NumField() + indirect := runtime.IfaceIndir(typ) + fieldIdx := 0 + disableIndirectConversion := false + var ( + head *Opcode + code *Opcode + prevField *Opcode + ) + ctx = ctx.incIndent() + tags := runtime.StructTags{} + anonymousFields := map[string][]structFieldPair{} + for i := 0; i < fieldNum; i++ { + field := typ.Field(i) + if runtime.IsIgnoredStructField(field) { + continue + } + tags = append(tags, runtime.StructTagFromField(field)) + } + for i, tag := range tags { + field := tag.Field + fieldType := runtime.Type2RType(field.Type) + fieldOpcodeIndex := ctx.opcodeIndex + fieldPtrIndex := ctx.ptrIndex + ctx.incIndex() + + nilcheck := true + addrForMarshaler := false + isIndirectSpecialCase := isPtr && i == 0 && fieldNum == 1 + isNilableType := isNilableType(fieldType) + + var valueCode *Opcode + switch { + case isIndirectSpecialCase && !isNilableType && isPtrMarshalJSONType(fieldType): + // *struct{ field T } => struct { field *T } + // func (*T) MarshalJSON() ([]byte, error) + // move pointer position from head to first field + code, err := compileMarshalJSON(ctx.withType(runtime.PtrTo(fieldType))) + if err != nil { + return nil, err + } + valueCode = code + nilcheck = false + indirect = false + disableIndirectConversion = true + case isIndirectSpecialCase && !isNilableType && isPtrMarshalTextType(fieldType): + // *struct{ field T } => struct { field *T } + // func (*T) MarshalText() ([]byte, error) + // move pointer position from head to first field + code, err := compileMarshalText(ctx.withType(runtime.PtrTo(fieldType))) + if err != nil { + return nil, err + } + valueCode = code + nilcheck = false + indirect = false + disableIndirectConversion = true + case isPtr && isPtrMarshalJSONType(fieldType): + // *struct{ field T } + // func (*T) MarshalJSON() ([]byte, error) + code, err := compileMarshalJSON(ctx.withType(fieldType)) + if err != nil { + return nil, err + } + addrForMarshaler = true + nilcheck = false + valueCode = code + case isPtr && isPtrMarshalTextType(fieldType): + // *struct{ field T } + // func (*T) MarshalText() ([]byte, error) + code, err := compileMarshalText(ctx.withType(fieldType)) + if err != nil { + return nil, err + } + addrForMarshaler = true + nilcheck = false + valueCode = code + default: + code, err := compile(ctx.withType(fieldType), isPtr) + if err != nil { + return nil, err + } + valueCode = code + } + + if field.Anonymous { + tagKey := "" + if tag.IsTaggedKey { + tagKey = tag.Key + } + for k, v := range anonymousStructFieldPairMap(tags, tagKey, valueCode) { + anonymousFields[k] = append(anonymousFields[k], v...) + } + valueCode.decIndent() + + // fix issue144 + if !(isPtr && strings.Contains(valueCode.Op.String(), "Marshal")) { + valueCode.Indirect = indirect + } + } else { + valueCode.Indirect = indirect + } + key := fmt.Sprintf(`"%s":`, tag.Key) + escapedKey := fmt.Sprintf(`%s:`, string(AppendEscapedString([]byte{}, tag.Key))) + fieldCode := &Opcode{ + Type: valueCode.Type, + DisplayIdx: fieldOpcodeIndex, + Idx: opcodeOffset(fieldPtrIndex), + Next: valueCode, + Indent: ctx.indent, + AnonymousKey: field.Anonymous, + Key: []byte(key), + EscapedKey: []byte(escapedKey), + IsTaggedKey: tag.IsTaggedKey, + DisplayKey: tag.Key, + Offset: field.Offset, + Indirect: indirect, + Nilcheck: nilcheck, + AddrForMarshaler: addrForMarshaler, + } + if fieldIdx == 0 { + fieldCode.HeadIdx = fieldCode.Idx + code = structHeader(ctx, fieldCode, valueCode, tag) + head = fieldCode + prevField = fieldCode + } else { + fieldCode.HeadIdx = head.HeadIdx + code.Next = fieldCode + code = structField(ctx, fieldCode, valueCode, tag) + prevField.NextField = fieldCode + fieldCode.PrevField = prevField + prevField = fieldCode + } + fieldIdx++ + } + ctx = ctx.decIndent() + + structEndCode := &Opcode{ + Op: OpStructEnd, + Type: nil, + Indent: ctx.indent, + Next: newEndOp(ctx), + } + + // no struct field + if head == nil { + head = &Opcode{ + Op: OpStructHead, + Type: typ, + DisplayIdx: ctx.opcodeIndex, + Idx: opcodeOffset(ctx.ptrIndex), + HeadIdx: opcodeOffset(ctx.ptrIndex), + Indent: ctx.indent, + NextField: structEndCode, + } + structEndCode.PrevField = head + ctx.incIndex() + code = head + } + + structEndCode.DisplayIdx = ctx.opcodeIndex + structEndCode.Idx = opcodeOffset(ctx.ptrIndex) + ctx.incIndex() + + if prevField != nil && prevField.NextField == nil { + prevField.NextField = structEndCode + structEndCode.PrevField = prevField + } + + head.End = structEndCode + code.Next = structEndCode + optimizeConflictAnonymousFields(anonymousFields) + optimizeAnonymousFields(head) + ret := (*Opcode)(unsafe.Pointer(head)) + compiled.Code = ret + + delete(ctx.structTypeToCompiledCode, typeptr) + + if !disableIndirectConversion && !head.Indirect && isPtr { + head.Indirect = true + } + + return ret, nil +} + +func isPtrMarshalJSONType(typ *runtime.Type) bool { + return !typ.Implements(marshalJSONType) && runtime.PtrTo(typ).Implements(marshalJSONType) +} + +func isPtrMarshalTextType(typ *runtime.Type) bool { + return !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType) +} diff --git a/internal/encoder/compiler/compiler.go b/internal/encoder/compiler/compiler.go deleted file mode 100644 index a20d4fe..0000000 --- a/internal/encoder/compiler/compiler.go +++ /dev/null @@ -1 +0,0 @@ -package compiler diff --git a/internal/encoder/compiler/norace.go b/internal/encoder/compiler/norace.go deleted file mode 100644 index 8299204..0000000 --- a/internal/encoder/compiler/norace.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !race - -package compiler - -import ( - "github.com/goccy/go-json/internal/encoder" -) - -func CompileToGetCodeSet(typeptr uintptr) (*encoder.OpcodeSet, error) { - return nil, nil -} diff --git a/internal/encoder/compiler_norace.go b/internal/encoder/compiler_norace.go new file mode 100644 index 0000000..f500779 --- /dev/null +++ b/internal/encoder/compiler_norace.go @@ -0,0 +1,38 @@ +// +build !race + +package encoder + +import ( + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) { + if typeptr > typeAddr.MaxTypeAddr { + return compileToGetCodeSetSlowPath(typeptr) + } + index := typeptr - typeAddr.BaseTypeAddr + if codeSet := cachedOpcodeSets[index]; codeSet != nil { + return codeSet, nil + } + + // noescape trick for header.typ ( reflect.*rtype ) + copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr)) + + code, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + }) + if err != nil { + return nil, err + } + code = copyOpcode(code) + codeLength := code.TotalLength() + codeSet := &OpcodeSet{ + Code: code, + CodeLength: codeLength, + } + cachedOpcodeSets[index] = codeSet + return codeSet, nil +} diff --git a/internal/encoder/compiler_race.go b/internal/encoder/compiler_race.go new file mode 100644 index 0000000..285b0ba --- /dev/null +++ b/internal/encoder/compiler_race.go @@ -0,0 +1,46 @@ +// +build race + +package encoder + +import ( + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +var setsMu sync.RWMutex + +func CompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) { + if typeptr > maxTypeAddr { + return compileToGetCodeSetSlowPath(typeptr) + } + index := typeptr - baseTypeAddr + setsMu.RLock() + if codeSet := cachedOpcodeSets[index]; codeSet != nil { + setsMu.RUnlock() + return codeSet, nil + } + setsMu.RUnlock() + + // noescape trick for header.typ ( reflect.*rtype ) + copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr)) + + code, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + }) + if err != nil { + return nil, err + } + code = copyOpcode(code) + codeLength := code.TotalLength() + codeSet := &opcodeSet{ + Code: code, + CodeLength: codeLength, + } + setsMu.Lock() + cachedOpcodeSets[index] = codeSet + setsMu.Unlock() + return codeSet, nil +} diff --git a/internal/encoder/context.go b/internal/encoder/context.go new file mode 100644 index 0000000..d21c008 --- /dev/null +++ b/internal/encoder/context.go @@ -0,0 +1,82 @@ +package encoder + +import ( + "github.com/goccy/go-json/internal/runtime" +) + +type compileContext struct { + typ *runtime.Type + opcodeIndex int + ptrIndex int + indent int + structTypeToCompiledCode map[uintptr]*CompiledCode + + parent *compileContext +} + +func (c *compileContext) context() *compileContext { + return &compileContext{ + typ: c.typ, + opcodeIndex: c.opcodeIndex, + ptrIndex: c.ptrIndex, + indent: c.indent, + structTypeToCompiledCode: c.structTypeToCompiledCode, + parent: c, + } +} + +func (c *compileContext) withType(typ *runtime.Type) *compileContext { + ctx := c.context() + ctx.typ = typ + return ctx +} + +func (c *compileContext) incIndent() *compileContext { + ctx := c.context() + ctx.indent++ + return ctx +} + +func (c *compileContext) decIndent() *compileContext { + ctx := c.context() + ctx.indent-- + return ctx +} + +func (c *compileContext) incIndex() { + c.incOpcodeIndex() + c.incPtrIndex() +} + +func (c *compileContext) decIndex() { + c.decOpcodeIndex() + c.decPtrIndex() +} + +func (c *compileContext) incOpcodeIndex() { + c.opcodeIndex++ + if c.parent != nil { + c.parent.incOpcodeIndex() + } +} + +func (c *compileContext) decOpcodeIndex() { + c.opcodeIndex-- + if c.parent != nil { + c.parent.decOpcodeIndex() + } +} + +func (c *compileContext) incPtrIndex() { + c.ptrIndex++ + if c.parent != nil { + c.parent.incPtrIndex() + } +} + +func (c *compileContext) decPtrIndex() { + c.ptrIndex-- + if c.parent != nil { + c.parent.decPtrIndex() + } +} diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index 26725fc..89410bf 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -24,41 +24,108 @@ const ( UnorderedMapOption ) -type Opcode struct { - Op OpType // operation type - Type *runtime.Type // go type - DisplayIdx int // opcode index - Key []byte // struct field key - EscapedKey []byte // struct field key ( HTML escaped ) - PtrNum int // pointer number: e.g. double pointer is 2. - DisplayKey string // key text to display - IsTaggedKey bool // whether tagged key - AnonymousKey bool // whether anonymous key - AnonymousHead bool // whether anonymous head or not - Indirect bool // whether indirect or not - Nilcheck bool // whether needs to nilcheck or not - AddrForMarshaler bool // whether needs to addr for marshaler or not - RshiftNum uint8 // use to take bit for judging whether negative integer or not - Mask uint64 // mask for number - Indent int // indent number +func (t OpType) IsMultipleOpHead() bool { + switch t { + case OpStructHead: + return true + case OpStructHeadSlice: + return true + case OpStructHeadArray: + return true + case OpStructHeadMap: + return true + case OpStructHeadStruct: + return true + case OpStructHeadOmitEmpty: + return true + case OpStructHeadOmitEmptySlice: + return true + case OpStructHeadStringTagSlice: + return true + case OpStructHeadOmitEmptyArray: + return true + case OpStructHeadStringTagArray: + return true + case OpStructHeadOmitEmptyMap: + return true + case OpStructHeadStringTagMap: + return true + case OpStructHeadOmitEmptyStruct: + return true + case OpStructHeadStringTag: + return true + case OpStructHeadSlicePtr: + return true + case OpStructHeadOmitEmptySlicePtr: + return true + case OpStructHeadStringTagSlicePtr: + return true + case OpStructHeadArrayPtr: + return true + case OpStructHeadOmitEmptyArrayPtr: + return true + case OpStructHeadStringTagArrayPtr: + return true + case OpStructHeadMapPtr: + return true + case OpStructHeadOmitEmptyMapPtr: + return true + case OpStructHeadStringTagMapPtr: + return true + } + return false +} - Idx uintptr // offset to access ptr - HeadIdx uintptr // offset to access slice/struct head - ElemIdx uintptr // offset to access array/slice/map elem - Length uintptr // offset to access slice/map length or array length - MapIter uintptr // offset to access map iterator - MapPos uintptr // offset to access position list for sorted map - Offset uintptr // offset size from struct header - Size uintptr // array/slice elem size - - MapKey *Opcode // map key - MapValue *Opcode // map value - Elem *Opcode // array/slice elem - End *Opcode // array/slice/struct/map end - PrevField *Opcode // prev struct field - NextField *Opcode // next struct field - Next *Opcode // next opcode - Jmp *CompiledCode // for recursive call +func (t OpType) IsMultipleOpField() bool { + switch t { + case OpStructField: + return true + case OpStructFieldSlice: + return true + case OpStructFieldArray: + return true + case OpStructFieldMap: + return true + case OpStructFieldStruct: + return true + case OpStructFieldOmitEmpty: + return true + case OpStructFieldOmitEmptySlice: + return true + case OpStructFieldStringTagSlice: + return true + case OpStructFieldOmitEmptyArray: + return true + case OpStructFieldStringTagArray: + return true + case OpStructFieldOmitEmptyMap: + return true + case OpStructFieldStringTagMap: + return true + case OpStructFieldOmitEmptyStruct: + return true + case OpStructFieldStringTag: + return true + case OpStructFieldSlicePtr: + return true + case OpStructFieldOmitEmptySlicePtr: + return true + case OpStructFieldStringTagSlicePtr: + return true + case OpStructFieldArrayPtr: + return true + case OpStructFieldOmitEmptyArrayPtr: + return true + case OpStructFieldStringTagArrayPtr: + return true + case OpStructFieldMapPtr: + return true + case OpStructFieldOmitEmptyMapPtr: + return true + case OpStructFieldStringTagMapPtr: + return true + } + return false } type OpcodeSet struct { diff --git a/internal/encoder/opcode.go b/internal/encoder/opcode.go new file mode 100644 index 0000000..674a71b --- /dev/null +++ b/internal/encoder/opcode.go @@ -0,0 +1,647 @@ +package encoder + +import ( + "fmt" + "math" + "strings" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +type Opcode struct { + Op OpType // operation type + Type *runtime.Type // go type + DisplayIdx int // opcode index + Key []byte // struct field key + EscapedKey []byte // struct field key ( HTML escaped ) + PtrNum int // pointer number: e.g. double pointer is 2. + DisplayKey string // key text to display + IsTaggedKey bool // whether tagged key + AnonymousKey bool // whether anonymous key + AnonymousHead bool // whether anonymous head or not + Indirect bool // whether indirect or not + Nilcheck bool // whether needs to nilcheck or not + AddrForMarshaler bool // whether needs to addr for marshaler or not + RshiftNum uint8 // use to take bit for judging whether negative integer or not + Mask uint64 // mask for number + Indent int // indent number + + Idx uintptr // offset to access ptr + HeadIdx uintptr // offset to access slice/struct head + ElemIdx uintptr // offset to access array/slice/map elem + Length uintptr // offset to access slice/map length or array length + MapIter uintptr // offset to access map iterator + MapPos uintptr // offset to access position list for sorted map + Offset uintptr // offset size from struct header + Size uintptr // array/slice elem size + + MapKey *Opcode // map key + MapValue *Opcode // map value + Elem *Opcode // array/slice elem + End *Opcode // array/slice/struct/map end + PrevField *Opcode // prev struct field + NextField *Opcode // next struct field + Next *Opcode // next opcode + Jmp *CompiledCode // for recursive call +} + +func rshitNum(bitSize uint8) uint8 { + return bitSize - 1 +} + +func (c *Opcode) setMaskAndRshiftNum(bitSize uint8) { + switch bitSize { + case 8: + c.Mask = math.MaxUint8 + case 16: + c.Mask = math.MaxUint16 + case 32: + c.Mask = math.MaxUint32 + case 64: + c.Mask = math.MaxUint64 + } + c.RshiftNum = rshitNum(bitSize) +} + +func (c *Opcode) ToHeaderType() OpType { + switch c.Op { + case OpInt: + return OpStructHeadInt + case OpIntPtr: + return OpStructHeadIntPtr + case OpUint: + return OpStructHeadUint + case OpUintPtr: + return OpStructHeadUintPtr + case OpFloat32: + return OpStructHeadFloat32 + case OpFloat32Ptr: + return OpStructHeadFloat32Ptr + case OpFloat64: + return OpStructHeadFloat64 + case OpFloat64Ptr: + return OpStructHeadFloat64Ptr + case OpString: + return OpStructHeadString + case OpStringPtr: + return OpStructHeadStringPtr + case OpNumber: + return OpStructHeadNumber + case OpNumberPtr: + return OpStructHeadNumberPtr + case OpBool: + return OpStructHeadBool + case OpBoolPtr: + return OpStructHeadBoolPtr + case OpMap: + return OpStructHeadMap + case OpMapPtr: + c.Op = OpMap + return OpStructHeadMapPtr + case OpArray: + return OpStructHeadArray + case OpArrayPtr: + c.Op = OpArray + return OpStructHeadArrayPtr + case OpSlice: + return OpStructHeadSlice + case OpSlicePtr: + c.Op = OpSlice + return OpStructHeadSlicePtr + case OpMarshalJSON: + return OpStructHeadMarshalJSON + case OpMarshalJSONPtr: + return OpStructHeadMarshalJSONPtr + case OpMarshalText: + return OpStructHeadMarshalText + case OpMarshalTextPtr: + return OpStructHeadMarshalTextPtr + } + return OpStructHead +} + +func (c *Opcode) ToFieldType() OpType { + switch c.Op { + case OpInt: + return OpStructFieldInt + case OpIntPtr: + return OpStructFieldIntPtr + case OpUint: + return OpStructFieldUint + case OpUintPtr: + return OpStructFieldUintPtr + case OpFloat32: + return OpStructFieldFloat32 + case OpFloat32Ptr: + return OpStructFieldFloat32Ptr + case OpFloat64: + return OpStructFieldFloat64 + case OpFloat64Ptr: + return OpStructFieldFloat64Ptr + case OpString: + return OpStructFieldString + case OpStringPtr: + return OpStructFieldStringPtr + case OpNumber: + return OpStructFieldNumber + case OpNumberPtr: + return OpStructFieldNumberPtr + case OpBool: + return OpStructFieldBool + case OpBoolPtr: + return OpStructFieldBoolPtr + case OpMap: + return OpStructFieldMap + case OpMapPtr: + c.Op = OpMap + return OpStructFieldMapPtr + case OpArray: + return OpStructFieldArray + case OpArrayPtr: + c.Op = OpArray + return OpStructFieldArrayPtr + case OpSlice: + return OpStructFieldSlice + case OpSlicePtr: + c.Op = OpSlice + return OpStructFieldSlicePtr + case OpMarshalJSON: + return OpStructFieldMarshalJSON + case OpMarshalJSONPtr: + return OpStructFieldMarshalJSONPtr + case OpMarshalText: + return OpStructFieldMarshalText + case OpMarshalTextPtr: + return OpStructFieldMarshalTextPtr + } + return OpStructField +} + +func newOpCode(ctx *compileContext, op OpType) *Opcode { + return newOpCodeWithNext(ctx, op, newEndOp(ctx)) +} + +func opcodeOffset(idx int) uintptr { + return uintptr(idx) * uintptrSize +} + +func copyOpcode(code *Opcode) *Opcode { + codeMap := map[uintptr]*Opcode{} + return code.copy(codeMap) +} + +func newOpCodeWithNext(ctx *compileContext, op OpType, next *Opcode) *Opcode { + return &Opcode{ + Op: op, + Type: ctx.typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + Idx: opcodeOffset(ctx.ptrIndex), + Next: next, + } +} + +func newEndOp(ctx *compileContext) *Opcode { + return newOpCodeWithNext(ctx, OpEnd, nil) +} + +func (c *Opcode) copy(codeMap map[uintptr]*Opcode) *Opcode { + if c == nil { + return nil + } + addr := uintptr(unsafe.Pointer(c)) + if code, exists := codeMap[addr]; exists { + return code + } + copied := &Opcode{ + Op: c.Op, + Type: c.Type, + DisplayIdx: c.DisplayIdx, + Key: c.Key, + EscapedKey: c.EscapedKey, + DisplayKey: c.DisplayKey, + PtrNum: c.PtrNum, + Mask: c.Mask, + RshiftNum: c.RshiftNum, + IsTaggedKey: c.IsTaggedKey, + AnonymousKey: c.AnonymousKey, + AnonymousHead: c.AnonymousHead, + Indirect: c.Indirect, + Nilcheck: c.Nilcheck, + AddrForMarshaler: c.AddrForMarshaler, + Indent: c.Indent, + Idx: c.Idx, + HeadIdx: c.HeadIdx, + ElemIdx: c.ElemIdx, + Length: c.Length, + MapIter: c.MapIter, + MapPos: c.MapPos, + Offset: c.Offset, + Size: c.Size, + } + codeMap[addr] = copied + copied.MapKey = c.MapKey.copy(codeMap) + copied.MapValue = c.MapValue.copy(codeMap) + copied.Elem = c.Elem.copy(codeMap) + copied.End = c.End.copy(codeMap) + copied.PrevField = c.PrevField.copy(codeMap) + copied.NextField = c.NextField.copy(codeMap) + copied.Next = c.Next.copy(codeMap) + copied.Jmp = c.Jmp + return copied +} + +func (c *Opcode) BeforeLastCode() *Opcode { + code := c + for { + var nextCode *Opcode + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + nextCode = code.End + default: + nextCode = code.Next + } + if nextCode.Op == OpEnd { + return code + } + code = nextCode + } +} + +func (c *Opcode) TotalLength() int { + var idx int + for code := c; code.Op != OpEnd; { + idx = int(code.Idx / uintptrSize) + if code.Op == OpStructFieldRecursiveEnd { + break + } + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } + return idx + 2 // opEnd + 1 +} + +func (c *Opcode) decOpcodeIndex() { + for code := c; code.Op != OpEnd; { + code.DisplayIdx-- + code.Idx -= uintptrSize + if code.HeadIdx > 0 { + code.HeadIdx -= uintptrSize + } + if code.ElemIdx > 0 { + code.ElemIdx -= uintptrSize + } + if code.MapIter > 0 { + code.MapIter -= uintptrSize + } + if code.Length > 0 && code.Op.CodeType() != CodeArrayHead && code.Op.CodeType() != CodeArrayElem { + code.Length -= uintptrSize + } + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } +} + +func (c *Opcode) decIndent() { + for code := c; code.Op != OpEnd; { + code.Indent-- + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } +} + +func (c *Opcode) dumpHead(code *Opcode) string { + var length uintptr + if code.Op.CodeType() == CodeArrayHead { + length = code.Length + } else { + length = code.Length / uintptrSize + } + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d])`, + code.DisplayIdx, + strings.Repeat("-", code.Indent), + code.Op, + code.Idx/uintptrSize, + code.HeadIdx/uintptrSize, + code.ElemIdx/uintptrSize, + length, + ) +} + +func (c *Opcode) dumpMapHead(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][mapIter:%d])`, + code.DisplayIdx, + strings.Repeat("-", code.Indent), + code.Op, + code.Idx/uintptrSize, + code.HeadIdx/uintptrSize, + code.ElemIdx/uintptrSize, + code.Length/uintptrSize, + code.MapIter/uintptrSize, + ) +} + +func (c *Opcode) dumpMapEnd(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`, + code.DisplayIdx, + strings.Repeat("-", code.Indent), + code.Op, + code.Idx/uintptrSize, + code.MapPos/uintptrSize, + code.Length/uintptrSize, + ) +} + +func (c *Opcode) dumpElem(code *Opcode) string { + var length uintptr + if code.Op.CodeType() == CodeArrayElem { + length = code.Length + } else { + length = code.Length / uintptrSize + } + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][size:%d])`, + code.DisplayIdx, + strings.Repeat("-", code.Indent), + code.Op, + code.Idx/uintptrSize, + code.HeadIdx/uintptrSize, + code.ElemIdx/uintptrSize, + length, + code.Size, + ) +} + +func (c *Opcode) dumpField(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][key:%s][offset:%d][headIdx:%d])`, + code.DisplayIdx, + strings.Repeat("-", code.Indent), + code.Op, + code.Idx/uintptrSize, + code.DisplayKey, + code.Offset, + code.HeadIdx/uintptrSize, + ) +} + +func (c *Opcode) dumpKey(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, + code.DisplayIdx, + strings.Repeat("-", code.Indent), + code.Op, + code.Idx/uintptrSize, + code.ElemIdx/uintptrSize, + code.Length/uintptrSize, + code.MapIter/uintptrSize, + ) +} + +func (c *Opcode) dumpValue(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][mapIter:%d])`, + code.DisplayIdx, + strings.Repeat("-", code.Indent), + code.Op, + code.Idx/uintptrSize, + code.MapIter/uintptrSize, + ) +} + +func (c *Opcode) dump() string { + codes := []string{} + for code := c; code.Op != OpEnd; { + switch code.Op.CodeType() { + case CodeSliceHead: + codes = append(codes, c.dumpHead(code)) + code = code.Next + case CodeMapHead: + codes = append(codes, c.dumpMapHead(code)) + code = code.Next + case CodeArrayElem, CodeSliceElem: + codes = append(codes, c.dumpElem(code)) + code = code.End + case CodeMapKey: + codes = append(codes, c.dumpKey(code)) + code = code.End + case CodeMapValue: + codes = append(codes, c.dumpValue(code)) + code = code.Next + case CodeMapEnd: + codes = append(codes, c.dumpMapEnd(code)) + code = code.Next + case CodeStructField: + codes = append(codes, c.dumpField(code)) + code = code.Next + case CodeStructEnd: + codes = append(codes, c.dumpField(code)) + code = code.Next + default: + codes = append(codes, fmt.Sprintf( + "[%d]%s%s ([idx:%d])", + code.DisplayIdx, + strings.Repeat("-", code.Indent), + code.Op, + code.Idx/uintptrSize, + )) + code = code.Next + } + } + return strings.Join(codes, "\n") +} + +func prevField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode { + if _, exists := removedFields[code]; exists { + return prevField(code.PrevField, removedFields) + } + return code +} + +func nextField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode { + if _, exists := removedFields[code]; exists { + return nextField(code.NextField, removedFields) + } + return code +} + +func linkPrevToNextField(cur *Opcode, removedFields map[*Opcode]struct{}) { + prev := prevField(cur.PrevField, removedFields) + prev.NextField = nextField(cur.NextField, removedFields) + code := prev + fcode := cur + for { + var nextCode *Opcode + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + nextCode = code.End + default: + nextCode = code.Next + } + if nextCode == fcode { + code.Next = fcode.Next + break + } else if nextCode.Op == OpEnd { + break + } + code = nextCode + } +} + +func newSliceHeaderCode(ctx *compileContext) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + elemIdx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + length := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpSlice, + DisplayIdx: ctx.opcodeIndex, + Idx: idx, + HeadIdx: idx, + ElemIdx: elemIdx, + Length: length, + Indent: ctx.indent, + } +} + +func newSliceElemCode(ctx *compileContext, head *Opcode, size uintptr) *Opcode { + return &Opcode{ + Op: OpSliceElem, + DisplayIdx: ctx.opcodeIndex, + Idx: opcodeOffset(ctx.ptrIndex), + HeadIdx: head.Idx, + ElemIdx: head.ElemIdx, + Length: head.Length, + Indent: ctx.indent, + Size: size, + } +} + +func newArrayHeaderCode(ctx *compileContext, alen int) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + elemIdx := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpArray, + DisplayIdx: ctx.opcodeIndex, + Idx: idx, + HeadIdx: idx, + ElemIdx: elemIdx, + Indent: ctx.indent, + Length: uintptr(alen), + } +} + +func newArrayElemCode(ctx *compileContext, head *Opcode, length int, size uintptr) *Opcode { + return &Opcode{ + Op: OpArrayElem, + DisplayIdx: ctx.opcodeIndex, + Idx: opcodeOffset(ctx.ptrIndex), + ElemIdx: head.ElemIdx, + HeadIdx: head.HeadIdx, + Length: uintptr(length), + Indent: ctx.indent, + Size: size, + } +} + +func newMapHeaderCode(ctx *compileContext) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + elemIdx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + length := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + mapIter := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpMap, + Type: ctx.typ, + DisplayIdx: ctx.opcodeIndex, + Idx: idx, + ElemIdx: elemIdx, + Length: length, + MapIter: mapIter, + Indent: ctx.indent, + } +} + +func newMapKeyCode(ctx *compileContext, head *Opcode) *Opcode { + return &Opcode{ + Op: OpMapKey, + DisplayIdx: ctx.opcodeIndex, + Idx: opcodeOffset(ctx.ptrIndex), + ElemIdx: head.ElemIdx, + Length: head.Length, + MapIter: head.MapIter, + Indent: ctx.indent, + } +} + +func newMapValueCode(ctx *compileContext, head *Opcode) *Opcode { + return &Opcode{ + Op: OpMapValue, + DisplayIdx: ctx.opcodeIndex, + Idx: opcodeOffset(ctx.ptrIndex), + ElemIdx: head.ElemIdx, + Length: head.Length, + MapIter: head.MapIter, + Indent: ctx.indent, + } +} + +func newMapEndCode(ctx *compileContext, head *Opcode) *Opcode { + mapPos := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + idx := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpMapEnd, + DisplayIdx: ctx.opcodeIndex, + Idx: idx, + Length: head.Length, + MapPos: mapPos, + Indent: ctx.indent, + Next: newEndOp(ctx), + } +} + +func newInterfaceCode(ctx *compileContext) *Opcode { + return &Opcode{ + Op: OpInterface, + Type: ctx.typ, + DisplayIdx: ctx.opcodeIndex, + Idx: opcodeOffset(ctx.ptrIndex), + Indent: ctx.indent, + Next: newEndOp(ctx), + } +} + +func newRecursiveCode(ctx *compileContext, jmp *CompiledCode) *Opcode { + return &Opcode{ + Op: OpStructFieldRecursive, + Type: ctx.typ, + DisplayIdx: ctx.opcodeIndex, + Idx: opcodeOffset(ctx.ptrIndex), + Indent: ctx.indent, + Next: newEndOp(ctx), + Jmp: jmp, + } +} diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index e7fddd4..ee8de9e 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -9,11 +9,10 @@ import ( "unsafe" "github.com/goccy/go-json/internal/encoder" - "github.com/goccy/go-json/internal/encoder/compiler" "github.com/goccy/go-json/internal/runtime" ) -const uintptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const +const uintptrSize = 4 << (^uintptr(0) >> 63) var ( load = encoder.Load @@ -173,7 +172,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := compiler.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) if err != nil { return nil, err } diff --git a/internal/runtime/struct_field.go b/internal/runtime/struct_field.go new file mode 100644 index 0000000..7700eb2 --- /dev/null +++ b/internal/runtime/struct_field.go @@ -0,0 +1,81 @@ +package runtime + +import ( + "reflect" + "strings" + "unicode" +) + +func getTag(field reflect.StructField) string { + return field.Tag.Get("json") +} + +func IsIgnoredStructField(field reflect.StructField) bool { + if field.PkgPath != "" { + if field.Anonymous { + if !(field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct) && field.Type.Kind() != reflect.Struct { + return true + } + } else { + // private field + return true + } + } + tag := getTag(field) + return tag == "-" +} + +type StructTag struct { + Key string + IsTaggedKey bool + IsOmitEmpty bool + IsString bool + Field reflect.StructField +} + +type StructTags []*StructTag + +func (t StructTags) ExistsKey(key string) bool { + for _, tt := range t { + if tt.Key == key { + return true + } + } + return false +} + +func isValidTag(s string) bool { + if s == "" { + return false + } + for _, c := range s { + switch { + case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): + // Backslash and quote chars are reserved, but + // otherwise any punctuation chars are allowed + // in a tag name. + case !unicode.IsLetter(c) && !unicode.IsDigit(c): + return false + } + } + return true +} + +func StructTagFromField(field reflect.StructField) *StructTag { + keyName := field.Name + tag := getTag(field) + st := &StructTag{Field: field} + opts := strings.Split(tag, ",") + if len(opts) > 0 { + if opts[0] != "" && isValidTag(opts[0]) { + keyName = opts[0] + st.IsTaggedKey = true + } + } + st.Key = keyName + if len(opts) > 1 { + st.IsOmitEmpty = opts[1] == "omitempty" + st.IsString = opts[1] == "string" + } + return st +} diff --git a/internal/runtime/type.go b/internal/runtime/type.go index fd425f7..88d05e1 100644 --- a/internal/runtime/type.go +++ b/internal/runtime/type.go @@ -1,9 +1,87 @@ package runtime -import "unsafe" +import ( + "reflect" + "unsafe" +) type SliceHeader struct { Data unsafe.Pointer Len int Cap int } + +const ( + maxAcceptableTypeAddrRange = 1024 * 1024 * 2 // 2 Mib +) + +type TypeAddr struct { + BaseTypeAddr uintptr + MaxTypeAddr uintptr + AddrRange uintptr +} + +var ( + typeAddr *TypeAddr + alreadyAnalyzed bool +) + +//go:linkname typelinks reflect.typelinks +func typelinks() ([]unsafe.Pointer, [][]int32) + +//go:linkname rtypeOff reflect.rtypeOff +func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer + +func AnalyzeTypeAddr() *TypeAddr { + defer func() { + alreadyAnalyzed = true + }() + if alreadyAnalyzed { + return typeAddr + } + sections, offsets := typelinks() + if len(sections) != 1 { + return nil + } + if len(offsets) != 1 { + return nil + } + section := sections[0] + offset := offsets[0] + var ( + min uintptr = uintptr(^uint(0)) + max uintptr = 0 + ) + for i := 0; i < len(offset); i++ { + typ := (*Type)(rtypeOff(section, offset[i])) + addr := uintptr(unsafe.Pointer(typ)) + if min > addr { + min = addr + } + if max < addr { + max = addr + } + if typ.Kind() == reflect.Ptr { + addr = uintptr(unsafe.Pointer(typ.Elem())) + if min > addr { + min = addr + } + if max < addr { + max = addr + } + } + } + addrRange := max - min + if addrRange == 0 { + return nil + } + if addrRange > maxAcceptableTypeAddrRange { + return nil + } + typeAddr = &TypeAddr{ + BaseTypeAddr: min, + MaxTypeAddr: max, + AddrRange: addrRange, + } + return typeAddr +} From 10c4118a454a9db94f267e03d110fc0964fbf66d Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Wed, 17 Mar 2021 00:22:19 +0900 Subject: [PATCH 05/15] Fix vm code --- encode.go | 30 +- internal/cmd/generator/main.go | 5 +- internal/encoder/compact.go | 56 ++ internal/encoder/compiler.go | 4 + internal/encoder/compiler_race.go | 6 +- internal/encoder/encoder.go | 34 +- internal/encoder/opcode.go | 2 +- internal/encoder/optype.go | 5 +- internal/encoder/vm/vm.go | 916 +++++++++++++++++++++++++++--- 9 files changed, 941 insertions(+), 117 deletions(-) create mode 100644 internal/encoder/compact.go diff --git a/encode.go b/encode.go index 7f22b25..814631b 100644 --- a/encode.go +++ b/encode.go @@ -13,7 +13,8 @@ import ( "sync" "unsafe" - _ "github.com/goccy/go-json/internal/encoder/vm" + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/encoder/vm" ) // An Encoder writes JSON values to an output stream. @@ -208,16 +209,29 @@ func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, p := uintptr(header.ptr) ctx.init(p, codeSet.codeLength) - buf, err := encodeRunCode(ctx, b, codeSet, opt) - ctx.keepRefs = append(ctx.keepRefs, header.ptr) - if err != nil { - return nil, err + if (opt & EncodeOptionHTMLEscape) != 0 { + buf, err := encodeRunCode(ctx, b, codeSet, opt) + if err != nil { + return nil, err + } + ctx.buf = buf + return buf, nil + } else { + codeSet, err := encoder.CompileToGetCodeSet(typeptr) + if err != nil { + return nil, err + } + ctx := &encoder.RuntimeContext{} + ctx.Init(p, codeSet.CodeLength) + buf, err := vm.Run(ctx, b, codeSet, encoder.Option(opt)) + if err != nil { + return nil, err + } + ctx.Buf = buf + return buf, nil } - - ctx.buf = buf - return buf, nil } func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { diff --git a/internal/cmd/generator/main.go b/internal/cmd/generator/main.go index 85fdadc..2bfb3b3 100644 --- a/internal/cmd/generator/main.go +++ b/internal/cmd/generator/main.go @@ -140,7 +140,7 @@ func (t OpType) HeadToPtrHead() OpType { if idx == -1 { return t } - suffix := "Ptr"+t.String()[idx+len("Head"):] + suffix := "PtrHead"+t.String()[idx+len("Head"):] const toPtrOffset = 3 if strings.Contains(OpType(int(t) + toPtrOffset).String(), suffix) { @@ -186,6 +186,9 @@ func (t OpType) FieldToEnd() OpType { return t } suffix := t.String()[idx+len("Field"):] + if suffix == "" || suffix == "OmitEmpty" || suffix == "StringTag" { + return t + } const toEndOffset = 3 if strings.Contains(OpType(int(t) + toEndOffset).String(), "End"+suffix) { return OpType(int(t) + toEndOffset) diff --git a/internal/encoder/compact.go b/internal/encoder/compact.go new file mode 100644 index 0000000..e5c5793 --- /dev/null +++ b/internal/encoder/compact.go @@ -0,0 +1,56 @@ +package encoder + +import ( + "bytes" + + "github.com/goccy/go-json/internal/errors" +) + +func compact(dst *bytes.Buffer, src []byte, escape bool) error { + if len(src) == 0 { + return errors.ErrUnexpectedEndOfJSON("", 0) + } + length := len(src) + for cursor := 0; cursor < length; cursor++ { + c := src[cursor] + switch c { + case ' ', '\t', '\n', '\r': + continue + case '"': + if err := dst.WriteByte(c); err != nil { + return err + } + for { + cursor++ + c := src[cursor] + if escape && (c == '<' || c == '>' || c == '&') { + if _, err := dst.WriteString(`\u00`); err != nil { + return err + } + if _, err := dst.Write([]byte{hex[c>>4], hex[c&0xF]}); err != nil { + return err + } + } else if err := dst.WriteByte(c); err != nil { + return err + } + switch c { + case '\\': + cursor++ + if err := dst.WriteByte(src[cursor]); err != nil { + return err + } + case '"': + goto LOOP_END + case '\000': + return errors.ErrUnexpectedEndOfJSON("string", int64(length)) + } + } + default: + if err := dst.WriteByte(c); err != nil { + return err + } + } + LOOP_END: + } + return nil +} diff --git a/internal/encoder/compiler.go b/internal/encoder/compiler.go index aa8d066..c52eaee 100644 --- a/internal/encoder/compiler.go +++ b/internal/encoder/compiler.go @@ -299,6 +299,10 @@ func compile(ctx *compileContext, isPtr bool) (*Opcode, error) { func convertPtrOp(code *Opcode) OpType { ptrHeadOp := code.Op.HeadToPtrHead() if code.Op != ptrHeadOp { + if code.PtrNum > 0 { + // ptr field and ptr head + code.PtrNum-- + } return ptrHeadOp } switch code.Op { diff --git a/internal/encoder/compiler_race.go b/internal/encoder/compiler_race.go index 285b0ba..827226c 100644 --- a/internal/encoder/compiler_race.go +++ b/internal/encoder/compiler_race.go @@ -12,10 +12,10 @@ import ( var setsMu sync.RWMutex func CompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) { - if typeptr > maxTypeAddr { + if typeptr > typeAddr.MaxTypeAddr { return compileToGetCodeSetSlowPath(typeptr) } - index := typeptr - baseTypeAddr + index := typeptr - typeAddr.BaseTypeAddr setsMu.RLock() if codeSet := cachedOpcodeSets[index]; codeSet != nil { setsMu.RUnlock() @@ -35,7 +35,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) { } code = copyOpcode(code) codeLength := code.TotalLength() - codeSet := &opcodeSet{ + codeSet := &OpcodeSet{ Code: code, CodeLength: codeLength, } diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index 89410bf..df98923 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -152,17 +152,22 @@ func Store(base uintptr, idx uintptr, p uintptr) { **(**uintptr)(unsafe.Pointer(&addr)) = p } -func LoadAndStoreNPtr(base uintptr, idx uintptr, ptrNum int) { +func LoadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { addr := base + idx p := **(**uintptr)(unsafe.Pointer(&addr)) - for i := 0; i < ptrNum; i++ { - if p == 0 { - **(**uintptr)(unsafe.Pointer(&addr)) = 0 - return - } - p = PtrToPtr(p) + if p == 0 { + return 0 } - **(**uintptr)(unsafe.Pointer(&addr)) = p + return PtrToPtr(p) + /* + for i := 0; i < ptrNum; i++ { + if p == 0 { + return p + } + p = PtrToPtr(p) + } + return p + */ } func PtrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } @@ -426,13 +431,12 @@ func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]by if err != nil { return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} } - return bb, nil - //buf := bytes.NewBuffer(b) - //TODO: we should validate buffer with `compact` - // if err := compact(buf, bb, escape); err != nil { - // return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} - // } - //return buf.Bytes(), nil + buf := bytes.NewBuffer(b) + // TODO: we should validate buffer with `compact` + if err := compact(buf, bb, escape); err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + return buf.Bytes(), nil } func AppendMarshalText(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { diff --git a/internal/encoder/opcode.go b/internal/encoder/opcode.go index 674a71b..24557cc 100644 --- a/internal/encoder/opcode.go +++ b/internal/encoder/opcode.go @@ -427,7 +427,7 @@ func (c *Opcode) dumpValue(code *Opcode) string { ) } -func (c *Opcode) dump() string { +func (c *Opcode) Dump() string { codes := []string{} for code := c; code.Op != OpEnd; { switch code.Op.CodeType() { diff --git a/internal/encoder/optype.go b/internal/encoder/optype.go index b0641c2..47d2647 100644 --- a/internal/encoder/optype.go +++ b/internal/encoder/optype.go @@ -955,7 +955,7 @@ func (t OpType) HeadToPtrHead() OpType { if idx == -1 { return t } - suffix := "Ptr" + t.String()[idx+len("Head"):] + suffix := "PtrHead" + t.String()[idx+len("Head"):] const toPtrOffset = 3 if strings.Contains(OpType(int(t)+toPtrOffset).String(), suffix) { @@ -1001,6 +1001,9 @@ func (t OpType) FieldToEnd() OpType { return t } suffix := t.String()[idx+len("Field"):] + if suffix == "" || suffix == "OmitEmpty" || suffix == "StringTag" { + return t + } const toEndOffset = 3 if strings.Contains(OpType(int(t)+toEndOffset).String(), "End"+suffix) { return OpType(int(t) + toEndOffset) diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index ee8de9e..5bddff4 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -1,4 +1,4 @@ -package json +package vm import ( "fmt" @@ -17,7 +17,7 @@ const uintptrSize = 4 << (^uintptr(0) >> 63) var ( load = encoder.Load store = encoder.Store - loadAndStoreNPtr = encoder.LoadAndStoreNPtr + loadNPtr = encoder.LoadNPtr ptrToPtr = encoder.PtrToPtr ptrToNPtr = encoder.PtrToNPtr ptrToUnsafePtr = encoder.PtrToUnsafePtr @@ -73,14 +73,28 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next store(ctxptr, code.Idx, ptrToPtr(p)) case encoder.OpIntPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpInt: b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) b = appendComma(b) code = code.Next case encoder.OpUintPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpUint: b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) @@ -99,14 +113,28 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpFloat32Ptr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpFloat32: b = appendFloat32(b, ptrToFloat32(load(ctxptr, code.Idx))) b = appendComma(b) code = code.Next case encoder.OpFloat64Ptr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpFloat64: v := ptrToFloat64(load(ctxptr, code.Idx)) @@ -117,28 +145,56 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStringPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpString: b = appendString(b, ptrToString(load(ctxptr, code.Idx))) b = appendComma(b) code = code.Next case encoder.OpBoolPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpBool: b = appendBool(b, ptrToBool(load(ctxptr, code.Idx))) b = appendComma(b) code = code.Next case encoder.OpBytesPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpBytes: b = appendByteSlice(b, ptrToBytes(load(ctxptr, code.Idx))) b = appendComma(b) code = code.Next case encoder.OpNumberPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpNumber: bb, err := appendNumber(b, ptrToNumber(load(ctxptr, code.Idx))) @@ -148,7 +204,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(bb) code = code.Next case encoder.OpInterfacePtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpInterface: p := load(ctxptr, code.Idx) @@ -206,7 +269,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = bb code = code.Next case encoder.OpMarshalJSONPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpMarshalJSON: p := load(ctxptr, code.Idx) @@ -223,7 +293,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(bb) code = code.Next case encoder.OpMarshalTextPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpMarshalText: p := load(ctxptr, code.Idx) @@ -240,7 +317,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(bb) code = code.Next case encoder.OpSlicePtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpSlice: p := load(ctxptr, code.Idx) @@ -278,7 +362,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.End.Next } case encoder.OpArrayPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpArray: p := load(ctxptr, code.Idx) @@ -313,7 +404,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.End.Next } case encoder.OpMapPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) fallthrough case encoder.OpMap: p := load(ctxptr, code.Idx) @@ -476,7 +574,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt ctxptr = ctx.Ptr() + offset ptrOffset = offset case encoder.OpStructPtrHead: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHead: p := load(ctxptr, code.Idx) @@ -498,7 +605,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next store(ctxptr, code.Idx, p) case encoder.OpStructPtrHeadOmitEmpty: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmpty: p := load(ctxptr, code.Idx) @@ -522,7 +638,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) } case encoder.OpStructPtrHeadStringTag: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTag: p := load(ctxptr, code.Idx) @@ -543,7 +668,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) case encoder.OpStructPtrHeadInt: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadInt: @@ -565,7 +699,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadOmitEmptyInt: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyInt: @@ -593,7 +736,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadStringTagInt: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadStringTagInt: @@ -616,7 +768,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadIntPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadIntPtr: p := load(ctxptr, code.Idx) @@ -643,7 +804,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyIntPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyIntPtr: p := load(ctxptr, code.Idx) @@ -668,7 +838,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } code = code.Next case encoder.OpStructPtrHeadStringTagIntPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTagIntPtr: p := load(ctxptr, code.Idx) @@ -698,7 +877,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadUint: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadUint: @@ -720,7 +908,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadOmitEmptyUint: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyUint: @@ -748,7 +945,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadStringTagUint: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadStringTagUint: @@ -771,7 +977,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadUintPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadUintPtr: p := load(ctxptr, code.Idx) @@ -798,7 +1013,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyUintPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyUintPtr: p := load(ctxptr, code.Idx) @@ -823,7 +1047,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } code = code.Next case encoder.OpStructPtrHeadStringTagUintPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTagUintPtr: p := load(ctxptr, code.Idx) @@ -853,7 +1086,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadFloat32: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadFloat32: @@ -875,7 +1117,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadOmitEmptyFloat32: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyFloat32: @@ -902,7 +1153,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadStringTagFloat32: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadStringTagFloat32: @@ -925,7 +1185,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadFloat32Ptr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadFloat32Ptr: p := load(ctxptr, code.Idx) @@ -952,7 +1221,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyFloat32Ptr: p := load(ctxptr, code.Idx) @@ -977,7 +1255,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } code = code.Next case encoder.OpStructPtrHeadStringTagFloat32Ptr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTagFloat32Ptr: p := load(ctxptr, code.Idx) @@ -1007,7 +1294,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadFloat64: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadFloat64: @@ -1033,7 +1329,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadOmitEmptyFloat64: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyFloat64: @@ -1063,7 +1368,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadStringTagFloat64: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadStringTagFloat64: @@ -1090,7 +1404,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadFloat64Ptr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadFloat64Ptr: p := load(ctxptr, code.Idx) @@ -1121,7 +1444,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyFloat64Ptr: p := load(ctxptr, code.Idx) @@ -1150,7 +1482,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } code = code.Next case encoder.OpStructPtrHeadStringTagFloat64Ptr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTagFloat64Ptr: p := load(ctxptr, code.Idx) @@ -1184,7 +1525,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadString: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadString: @@ -1206,7 +1556,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadOmitEmptyString: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyString: @@ -1233,7 +1592,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadStringTagString: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadStringTagString: @@ -1255,7 +1623,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadStringPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringPtr: p := load(ctxptr, code.Idx) @@ -1282,7 +1659,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyStringPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyStringPtr: p := load(ctxptr, code.Idx) @@ -1307,7 +1693,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } code = code.Next case encoder.OpStructPtrHeadStringTagStringPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTagStringPtr: p := load(ctxptr, code.Idx) @@ -1335,7 +1730,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadBool: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadBool: @@ -1357,7 +1761,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadOmitEmptyBool: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyBool: @@ -1384,7 +1797,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadStringTagBool: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadStringTagBool: @@ -1407,7 +1829,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadBoolPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadBoolPtr: p := load(ctxptr, code.Idx) @@ -1434,7 +1865,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyBoolPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyBoolPtr: p := load(ctxptr, code.Idx) @@ -1459,7 +1899,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } code = code.Next case encoder.OpStructPtrHeadStringTagBoolPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTagBoolPtr: p := load(ctxptr, code.Idx) @@ -1489,7 +1938,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadBytes: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadBytes: @@ -1511,7 +1969,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadOmitEmptyBytes: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyBytes: @@ -1538,7 +2005,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadStringTagBytes: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadStringTagBytes: @@ -1561,7 +2037,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadBytesPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadBytesPtr: p := load(ctxptr, code.Idx) @@ -1588,7 +2073,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyBytesPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyBytesPtr: p := load(ctxptr, code.Idx) @@ -1613,7 +2107,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } code = code.Next case encoder.OpStructPtrHeadStringTagBytesPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTagBytesPtr: p := load(ctxptr, code.Idx) @@ -1643,7 +2146,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadNumber: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadNumber: @@ -1668,7 +2180,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next case encoder.OpStructPtrHeadOmitEmptyNumber: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyNumber: @@ -1698,7 +2219,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadStringTagNumber: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadStringTagNumber: @@ -1724,7 +2254,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadNumberPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadNumberPtr: p := load(ctxptr, code.Idx) @@ -1755,7 +2294,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyNumberPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyNumberPtr: p := load(ctxptr, code.Idx) @@ -1783,7 +2331,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } code = code.Next case encoder.OpStructPtrHeadStringTagNumberPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadStringTagNumberPtr: p := load(ctxptr, code.Idx) @@ -1817,7 +2374,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadStringTagArray, encoder.OpStructPtrHeadSlice, encoder.OpStructPtrHeadStringTagSlice: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadArray, encoder.OpStructHeadStringTagArray, @@ -1840,7 +2406,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) case encoder.OpStructPtrHeadOmitEmptyArray: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptyArray: @@ -1862,7 +2437,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) case encoder.OpStructPtrHeadOmitEmptySlice: if code.Indirect { - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) } fallthrough case encoder.OpStructHeadOmitEmptySlice: @@ -1889,7 +2473,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadStringTagArrayPtr, encoder.OpStructPtrHeadSlicePtr, encoder.OpStructPtrHeadStringTagSlicePtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadStringTagArrayPtr, encoder.OpStructHeadSlicePtr, encoder.OpStructHeadStringTagSlicePtr: @@ -1918,7 +2511,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) } case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: p := load(ctxptr, code.Idx) @@ -1944,7 +2546,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) } case encoder.OpStructPtrHeadMap, encoder.OpStructPtrHeadStringTagMap: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadMap, encoder.OpStructHeadStringTagMap: p := load(ctxptr, code.Idx) @@ -1966,7 +2577,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next store(ctxptr, code.Idx, p) case encoder.OpStructPtrHeadOmitEmptyMap: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyMap: p := load(ctxptr, code.Idx) @@ -1992,7 +2612,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) } case encoder.OpStructPtrHeadMapPtr, encoder.OpStructPtrHeadStringTagMapPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadMapPtr, encoder.OpStructHeadStringTagMapPtr: p := load(ctxptr, code.Idx) @@ -2027,7 +2656,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) } case encoder.OpStructPtrHeadOmitEmptyMapPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyMapPtr: p := load(ctxptr, code.Idx) @@ -2058,7 +2696,18 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt store(ctxptr, code.Idx, p) } case encoder.OpStructPtrHeadMarshalJSON: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } fallthrough case encoder.OpStructHeadMarshalJSON: p := load(ctxptr, code.Idx) @@ -2091,7 +2740,18 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadStringTagMarshalJSON: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } fallthrough case encoder.OpStructHeadStringTagMarshalJSON: p := load(ctxptr, code.Idx) @@ -2124,7 +2784,18 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } fallthrough case encoder.OpStructHeadOmitEmptyMarshalJSON: p := load(ctxptr, code.Idx) @@ -2157,7 +2828,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next } case encoder.OpStructPtrHeadMarshalJSONPtr, encoder.OpStructPtrHeadStringTagMarshalJSONPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadMarshalJSONPtr, encoder.OpStructHeadStringTagMarshalJSONPtr: p := load(ctxptr, code.Idx) @@ -2188,7 +2868,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: p := load(ctxptr, code.Idx) @@ -2219,7 +2908,18 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next } case encoder.OpStructPtrHeadMarshalText: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } fallthrough case encoder.OpStructHeadMarshalText: p := load(ctxptr, code.Idx) @@ -2252,7 +2952,18 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadStringTagMarshalText: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } fallthrough case encoder.OpStructHeadStringTagMarshalText: p := load(ctxptr, code.Idx) @@ -2285,7 +2996,18 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyMarshalText: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } fallthrough case encoder.OpStructHeadOmitEmptyMarshalText: p := load(ctxptr, code.Idx) @@ -2318,7 +3040,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next } case encoder.OpStructPtrHeadMarshalTextPtr, encoder.OpStructPtrHeadStringTagMarshalTextPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadMarshalTextPtr, encoder.OpStructHeadStringTagMarshalTextPtr: p := load(ctxptr, code.Idx) @@ -2349,7 +3080,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(b) code = code.Next case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: - loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) fallthrough case encoder.OpStructHeadOmitEmptyMarshalTextPtr: p := load(ctxptr, code.Idx) @@ -3078,12 +3818,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldMap, encoder.OpStructFieldStringTagMap: b = append(b, code.Key...) p := load(ctxptr, code.HeadIdx) - p = ptrToNPtr(p+code.Offset, code.PtrNum) + p = ptrToNPtr(p+code.Offset, code.PtrNum+1) code = code.Next store(ctxptr, code.Idx, p) case encoder.OpStructFieldOmitEmptyMap: p := load(ctxptr, code.HeadIdx) - p = ptrToNPtr(p+code.Offset, code.PtrNum) + p = ptrToNPtr(p+code.Offset, code.PtrNum+1) if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { code = code.NextField } else { From cccf9f9f333f1902bb64537e1556b3b7b87c8a32 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Wed, 17 Mar 2021 12:32:23 +0900 Subject: [PATCH 06/15] Replace vm and escaped vm codes with internal package --- docker-compose.yml | 2 +- encode.go | 83 +- encode_vm.go | 4050 -------------------------- encode_vm_escaped.go | 4091 -------------------------- internal/encoder/compiler_race.go | 2 +- internal/encoder/encoder.go | 11 + internal/encoder/vm/vm.go | 14 +- internal/encoder/vm_escaped/vm.go | 4500 +++++++++++++++++++++++++++++ 8 files changed, 4565 insertions(+), 8188 deletions(-) delete mode 100644 encode_vm_escaped.go create mode 100644 internal/encoder/vm_escaped/vm.go diff --git a/docker-compose.yml b/docker-compose.yml index d1aa385..68f12b1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: deploy: resources: limits: - memory: 2048M + memory: 1200M working_dir: /go/src/go-json command: | sh -c "go test -c . && ls go-json.test" diff --git a/encode.go b/encode.go index 814631b..9aee645 100644 --- a/encode.go +++ b/encode.go @@ -15,6 +15,7 @@ import ( "github.com/goccy/go-json/internal/encoder" "github.com/goccy/go-json/internal/encoder/vm" + "github.com/goccy/go-json/internal/encoder/vm_escaped" ) // An Encoder writes JSON values to an output stream. @@ -48,6 +49,15 @@ var ( } }, } + encRuntimeContextPool2 = sync.Pool{ + New: func() interface{} { + return &encoder.RuntimeContext{ + Buf: make([]byte, 0, bufSize), + Ptrs: make([]uintptr, 128), + KeepRefs: make([]unsafe.Pointer, 0, 8), + } + }, + } ) func takeEncodeRuntimeContext() *encodeRuntimeContext { @@ -58,6 +68,14 @@ func releaseEncodeRuntimeContext(ctx *encodeRuntimeContext) { encRuntimeContextPool.Put(ctx) } +func takeEncodeRuntimeContext2() *encoder.RuntimeContext { + return encRuntimeContextPool2.Get().(*encoder.RuntimeContext) +} + +func releaseEncodeRuntimeContext2(ctx *encoder.RuntimeContext) { + encRuntimeContextPool2.Put(ctx) +} + // NewEncoder returns a new encoder that writes to w. func NewEncoder(w io.Writer) *Encoder { return &Encoder{w: w, enabledHTMLEscape: true} @@ -95,7 +113,9 @@ func (e *Encoder) encodeWithOption(ctx *encodeRuntimeContext, v interface{}, opt if e.enabledIndent { buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr, opt) } else { + ctx := takeEncodeRuntimeContext2() buf, err = encode(ctx, v, opt) + releaseEncodeRuntimeContext2(ctx) } if err != nil { return err @@ -133,11 +153,11 @@ func (e *Encoder) SetIndent(prefix, indent string) { } func marshal(v interface{}, opt EncodeOption) ([]byte, error) { - ctx := takeEncodeRuntimeContext() + ctx := takeEncodeRuntimeContext2() buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape) if err != nil { - releaseEncodeRuntimeContext(ctx) + releaseEncodeRuntimeContext2(ctx) return nil, err } @@ -149,16 +169,16 @@ func marshal(v interface{}, opt EncodeOption) ([]byte, error) { copied := make([]byte, len(buf)) copy(copied, buf) - releaseEncodeRuntimeContext(ctx) + releaseEncodeRuntimeContext2(ctx) return copied, nil } func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) { - ctx := takeEncodeRuntimeContext() + ctx := takeEncodeRuntimeContext2() buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape) if err != nil { - releaseEncodeRuntimeContext(ctx) + releaseEncodeRuntimeContext2(ctx) return nil, err } @@ -170,7 +190,7 @@ func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) { copied := make([]byte, len(buf)) copy(copied, buf) - releaseEncodeRuntimeContext(ctx) + releaseEncodeRuntimeContext2(ctx) return copied, nil } @@ -191,8 +211,8 @@ func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]by return copied, nil } -func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { - b := ctx.buf[:0] +func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { + b := ctx.Buf[:0] if v == nil { b = encodeNull(b) b = encodeComma(b) @@ -202,40 +222,25 @@ func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, typ := header.typ typeptr := uintptr(unsafe.Pointer(typ)) - codeSet, err := encodeCompileToGetCodeSet(typeptr) + codeSet, err := encoder.CompileToGetCodeSet(typeptr) if err != nil { return nil, err } p := uintptr(header.ptr) - ctx.init(p, codeSet.codeLength) - ctx.keepRefs = append(ctx.keepRefs, header.ptr) + ctx.Init(p, codeSet.CodeLength) + ctx.KeepRefs = append(ctx.KeepRefs, header.ptr) - if (opt & EncodeOptionHTMLEscape) != 0 { - buf, err := encodeRunCode(ctx, b, codeSet, opt) - if err != nil { - return nil, err - } - ctx.buf = buf - return buf, nil - } else { - codeSet, err := encoder.CompileToGetCodeSet(typeptr) - if err != nil { - return nil, err - } - ctx := &encoder.RuntimeContext{} - ctx.Init(p, codeSet.CodeLength) - buf, err := vm.Run(ctx, b, codeSet, encoder.Option(opt)) - if err != nil { - return nil, err - } - ctx.Buf = buf - return buf, nil + buf, err := encodeRunCode(ctx, b, codeSet, opt) + if err != nil { + return nil, err } + ctx.Buf = buf + return buf, nil } -func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { - b := ctx.buf[:0] +func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { + b := ctx.Buf[:0] if v == nil { b = encodeNull(b) b = encodeComma(b) @@ -245,19 +250,19 @@ func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) typ := header.typ typeptr := uintptr(unsafe.Pointer(typ)) - codeSet, err := encodeCompileToGetCodeSet(typeptr) + codeSet, err := encoder.CompileToGetCodeSet(typeptr) if err != nil { return nil, err } p := uintptr(header.ptr) - ctx.init(p, codeSet.codeLength) + ctx.Init(p, codeSet.CodeLength) buf, err := encodeRunCode(ctx, b, codeSet, opt) if err != nil { return nil, err } - ctx.buf = buf + ctx.Buf = buf return buf, nil } @@ -291,11 +296,11 @@ func encodeIndent(ctx *encodeRuntimeContext, v interface{}, prefix, indent strin return buf, nil } -func encodeRunCode(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt EncodeOption) ([]byte, error) { +func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) { if (opt & EncodeOptionHTMLEscape) != 0 { - return encodeRunEscaped(ctx, b, codeSet, opt) + return vm_escaped.Run(ctx, b, codeSet, encoder.Option(opt)) } - return encodeRun(ctx, b, codeSet, opt) + return vm.Run(ctx, b, codeSet, encoder.Option(opt)) } func encodeRunIndentCode(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, prefix, indent string, opt EncodeOption) ([]byte, error) { diff --git a/encode_vm.go b/encode_vm.go index 510f105..3893ce1 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -2,11 +2,8 @@ package json import ( "fmt" - "math" "reflect" - "sort" "strconv" - "strings" "unsafe" ) @@ -67,4050 +64,3 @@ func errMarshalerWithCode(code *opcode, err error) *MarshalerError { Err: err, } } - -func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt EncodeOption) ([]byte, error) { - recursiveLevel := 0 - ptrOffset := uintptr(0) - ctxptr := ctx.ptr() - code := codeSet.code - - for { - switch code.op { - default: - return nil, fmt.Errorf("encoder: opcode %s has not been implemented", code.op) - case opPtr: - ptr := load(ctxptr, code.idx) - code = code.next - store(ctxptr, code.idx, ptrToPtr(ptr)) - case opInt: - b = appendInt(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = encodeComma(b) - code = code.next - case opUint: - b = appendUint(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = encodeComma(b) - code = code.next - case opIntString: - b = append(b, '"') - b = appendInt(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opUintString: - b = append(b, '"') - b = appendUint(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opFloat32: - b = encodeFloat32(b, ptrToFloat32(load(ctxptr, code.idx))) - b = encodeComma(b) - code = code.next - case opFloat64: - v := ptrToFloat64(load(ctxptr, code.idx)) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - case opString: - b = encodeNoEscapedString(b, ptrToString(load(ctxptr, code.idx))) - b = encodeComma(b) - code = code.next - case opBool: - b = encodeBool(b, ptrToBool(load(ctxptr, code.idx))) - b = encodeComma(b) - code = code.next - case opBytes: - p := load(ctxptr, code.idx) - slice := ptrToSlice(p) - if p == 0 || slice.data == nil { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeComma(b) - code = code.next - case opNumber: - bb, err := encodeNumber(b, ptrToNumber(load(ctxptr, code.idx))) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opInterfacePtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opInterface: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - for _, seen := range ctx.seenPtr { - if ptr == seen { - return nil, errUnsupportedValue(code, ptr) - } - } - ctx.seenPtr = append(ctx.seenPtr, ptr) - iface := (*emptyInterface)(ptrToUnsafePtr(ptr)) - if iface == nil || iface.ptr == nil { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := encodeCompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) - if err != nil { - return nil, err - } - - totalLength := uintptr(codeSet.codeLength) - nextTotalLength := uintptr(ifaceCodeSet.codeLength) - - curlen := uintptr(len(ctx.ptrs)) - offsetNum := ptrOffset / uintptrSize - - newLen := offsetNum + totalLength + nextTotalLength - if curlen < newLen { - ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...) - } - oldPtrs := ctx.ptrs - - newPtrs := ctx.ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] - newPtrs[0] = uintptr(iface.ptr) - - ctx.ptrs = newPtrs - - bb, err := encodeRun(ctx, b, ifaceCodeSet, opt) - if err != nil { - return nil, err - } - - ctx.ptrs = oldPtrs - ctxptr = ctx.ptr() - ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1] - - b = bb - code = code.next - case opMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - b = append(b, `""`...) - b = encodeComma(b) - code = code.next - break - } - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opSlice: - p := load(ctxptr, code.idx) - slice := ptrToSlice(p) - if p == 0 || slice.data == nil { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.elemIdx, 0) - store(ctxptr, code.length, uintptr(slice.len)) - store(ctxptr, code.idx, uintptr(slice.data)) - if slice.len > 0 { - b = append(b, '[') - code = code.next - store(ctxptr, code.idx, uintptr(slice.data)) - } else { - b = append(b, '[', ']', ',') - code = code.end.next - } - case opSliceElem: - idx := load(ctxptr, code.elemIdx) - length := load(ctxptr, code.length) - idx++ - if idx < length { - store(ctxptr, code.elemIdx, idx) - data := load(ctxptr, code.headIdx) - size := code.size - code = code.next - store(ctxptr, code.idx, data+idx*size) - } else { - last := len(b) - 1 - b[last] = ']' - b = encodeComma(b) - code = code.end.next - } - case opArray: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - } else { - if code.length > 0 { - b = append(b, '[') - store(ctxptr, code.elemIdx, 0) - code = code.next - store(ctxptr, code.idx, p) - } else { - b = append(b, '[', ']', ',') - code = code.end.next - } - } - case opArrayElem: - idx := load(ctxptr, code.elemIdx) - idx++ - if idx < code.length { - store(ctxptr, code.elemIdx, idx) - p := load(ctxptr, code.headIdx) - size := code.size - code = code.next - store(ctxptr, code.idx, p+idx*size) - } else { - last := len(b) - 1 - b[last] = ']' - b = encodeComma(b) - code = code.end.next - } - case opMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opMap: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - uptr := ptrToUnsafePtr(p) - mlen := maplen(uptr) - if mlen > 0 { - b = append(b, '{') - iter := mapiterinit(code.typ, uptr) - ctx.keepRefs = append(ctx.keepRefs, iter) - store(ctxptr, code.elemIdx, 0) - store(ctxptr, code.length, uintptr(mlen)) - store(ctxptr, code.mapIter, uintptr(iter)) - if (opt & EncodeOptionUnorderedMap) == 0 { - mapCtx := newMapContext(mlen) - mapCtx.pos = append(mapCtx.pos, len(b)) - ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx)) - store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx))) - } - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - b = append(b, '{', '}', ',') - code = code.end.next - } - case opMapKey: - idx := load(ctxptr, code.elemIdx) - length := load(ctxptr, code.length) - idx++ - if (opt & EncodeOptionUnorderedMap) != 0 { - if idx < length { - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - store(ctxptr, code.elemIdx, idx) - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - last := len(b) - 1 - b[last] = '}' - b = encodeComma(b) - code = code.end.next - } - } else { - ptr := load(ctxptr, code.end.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - mapCtx.pos = append(mapCtx.pos, len(b)) - if idx < length { - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - store(ctxptr, code.elemIdx, idx) - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - code = code.end - } - } - case opMapValue: - if (opt & EncodeOptionUnorderedMap) != 0 { - last := len(b) - 1 - b[last] = ':' - } else { - ptr := load(ctxptr, code.end.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - mapCtx.pos = append(mapCtx.pos, len(b)) - } - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - value := mapitervalue(iter) - store(ctxptr, code.next.idx, uintptr(value)) - mapiternext(iter) - code = code.next - case opMapEnd: - // this operation only used by sorted map. - length := int(load(ctxptr, code.length)) - ptr := load(ctxptr, code.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - pos := mapCtx.pos - for i := 0; i < length; i++ { - startKey := pos[i*2] - startValue := pos[i*2+1] - var endValue int - if i+1 < length { - endValue = pos[i*2+2] - } else { - endValue = len(b) - } - mapCtx.slice.items = append(mapCtx.slice.items, mapItem{ - key: b[startKey:startValue], - value: b[startValue:endValue], - }) - } - sort.Sort(mapCtx.slice) - buf := mapCtx.buf - for _, item := range mapCtx.slice.items { - buf = append(buf, item.key...) - buf[len(buf)-1] = ':' - buf = append(buf, item.value...) - } - buf[len(buf)-1] = '}' - buf = append(buf, ',') - b = b[:pos[0]] - b = append(b, buf...) - mapCtx.buf = buf - releaseMapContext(mapCtx) - code = code.next - case opStructFieldRecursivePtr: - p := load(ctxptr, code.idx) - if p == 0 { - code = code.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldRecursive: - ptr := load(ctxptr, code.idx) - if ptr != 0 { - if recursiveLevel > startDetectingCyclesAfter { - for _, seen := range ctx.seenPtr { - if ptr == seen { - return nil, errUnsupportedValue(code, ptr) - } - } - } - } - ctx.seenPtr = append(ctx.seenPtr, ptr) - c := code.jmp.code - curlen := uintptr(len(ctx.ptrs)) - offsetNum := ptrOffset / uintptrSize - oldOffset := ptrOffset - ptrOffset += code.jmp.curLen * uintptrSize - - newLen := offsetNum + code.jmp.curLen + code.jmp.nextLen - if curlen < newLen { - ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...) - } - ctxptr = ctx.ptr() + ptrOffset // assign new ctxptr - - store(ctxptr, c.idx, ptr) - store(ctxptr, c.end.next.idx, oldOffset) - store(ctxptr, c.end.next.elemIdx, uintptr(unsafe.Pointer(code.next))) - code = c - recursiveLevel++ - case opStructFieldRecursiveEnd: - recursiveLevel-- - - // restore ctxptr - offset := load(ctxptr, code.idx) - ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1] - - codePtr := load(ctxptr, code.elemIdx) - code = (*opcode)(ptrToUnsafePtr(codePtr)) - ctxptr = ctx.ptr() + offset - ptrOffset = offset - case opStructFieldPtrHead: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHead: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if !code.anonymousKey { - b = append(b, code.key...) - } - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmpty: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmpty: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - p += code.offset - if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) { - code = code.nextField - } else { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadStringTag: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTag: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - p += code.offset - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = appendInt(b, ptrToUint64(p+code.offset), code) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - u64 := ptrToUint64(p + code.offset) - v := u64 & code.mask - if v == 0 { - code = code.nextField - } else { - b = append(b, code.key...) - b = appendInt(b, u64, code) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = append(b, '"') - b = appendInt(b, ptrToUint64(p+code.offset), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - b = appendInt(b, ptrToUint64(p), code) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = appendUint(b, ptrToUint64(p+code.offset), code) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - u64 := ptrToUint64(p + code.offset) - v := u64 & code.mask - if v == 0 { - code = code.nextField - } else { - b = append(b, code.key...) - b = appendUint(b, u64, code) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = append(b, '"') - b = appendUint(b, ptrToUint64(p+code.offset), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - b = appendUint(b, ptrToUint64(p), code) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = encodeFloat32(b, ptrToFloat32(p+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToFloat32(p + code.offset) - if v == 0 { - code = code.nextField - } else { - b = append(b, code.key...) - b = encodeFloat32(b, v) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - b = encodeFloat32(b, ptrToFloat32(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToFloat64(p + code.offset) - if v == 0 { - code = code.nextField - } else { - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.key...) - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.key...) - b = append(b, '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = encodeNoEscapedString(b, ptrToString(p+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToString(p + code.offset) - if v == "" { - code = code.nextField - } else { - b = append(b, code.key...) - b = encodeNoEscapedString(b, v) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - s := ptrToString(p + code.offset) - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, s))) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, ptrToString(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - b = encodeNoEscapedString(b, ptrToString(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, ptrToString(p)))) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = encodeBool(b, ptrToBool(p+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToBool(p + code.offset) - if v { - b = append(b, code.key...) - b = encodeBool(b, v) - b = encodeComma(b) - code = code.next - } else { - code = code.nextField - } - case opStructFieldPtrHeadStringTagBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = append(b, '"') - b = encodeBool(b, ptrToBool(p+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - b = encodeBool(b, ptrToBool(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToBytes(p + code.offset) - if v == nil { - code = code.nextField - } else { - b = append(b, code.key...) - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = append(b, '"') - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeByteSlice(b, ptrToBytes(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldHeadNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opStructFieldPtrHeadOmitEmptyNumber: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToNumber(p + code.offset) - if v == "" { - code = code.nextField - } else { - b = append(b, code.key...) - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - } - case opStructFieldPtrHeadStringTagNumber: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldPtrHeadStringTagNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadArray, opStructFieldPtrHeadStringTagArray, - opStructFieldPtrHeadSlice, opStructFieldPtrHeadStringTagSlice: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadArray, opStructFieldHeadStringTagArray, - opStructFieldHeadSlice, opStructFieldHeadStringTagSlice: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptyArray: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyArray: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - p += code.offset - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptySlice: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptySlice: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - p += code.offset - slice := ptrToSlice(p) - if slice.data == nil { - code = code.nextField - } else { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadArrayPtr, opStructFieldPtrHeadStringTagArrayPtr, - opStructFieldPtrHeadSlicePtr, opStructFieldPtrHeadStringTagSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadArrayPtr, opStructFieldHeadStringTagArrayPtr, - opStructFieldHeadSlicePtr, opStructFieldHeadStringTagSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.nextField - } else { - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadOmitEmptyArrayPtr, opStructFieldPtrHeadOmitEmptySlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyArrayPtr, opStructFieldHeadOmitEmptySlicePtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - code = code.nextField - } else { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMap, opStructFieldPtrHeadStringTagMap: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMap, opStructFieldHeadStringTagMap: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if p != 0 && code.indirect { - p = ptrToPtr(p + code.offset) - } - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptyMap: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMap: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if p != 0 && code.indirect { - p = ptrToPtr(p + code.offset) - } - if maplen(ptrToUnsafePtr(p)) == 0 { - code = code.nextField - } else { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMapPtr, opStructFieldPtrHeadStringTagMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMapPtr, opStructFieldHeadStringTagMapPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.nextField - break - } - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.nextField - } else { - if code.indirect { - p = ptrToPtr(p) - } - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadOmitEmptyMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMapPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if p == 0 { - code = code.nextField - break - } - p = ptrToPtr(p + code.offset) - if p == 0 { - code = code.nextField - } else { - if code.indirect { - p = ptrToPtr(p) - } - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadStringTagMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadStringTagMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadStringTagMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadOmitEmptyMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadOmitEmptyMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if p == 0 && code.nilcheck { - code = code.nextField - } else { - b = append(b, code.key...) - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalJSONPtr, opStructFieldPtrHeadStringTagMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMarshalJSONPtr, opStructFieldHeadStringTagMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if !code.anonymousHead { - b = append(b, '{') - } - if p == 0 { - code = code.nextField - } else { - b = append(b, code.key...) - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadStringTagMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadStringTagMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadStringTagMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadOmitEmptyMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadOmitEmptyMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if p == 0 && code.nilcheck { - code = code.nextField - } else { - b = append(b, code.key...) - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalTextPtr, opStructFieldPtrHeadStringTagMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMarshalTextPtr, opStructFieldHeadStringTagMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.key...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if !code.anonymousHead { - b = append(b, '{') - } - if p == 0 { - code = code.nextField - } else { - b = append(b, code.key...) - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - b = encodeComma(b) - code = code.next - } - case opStructField: - if !code.anonymousKey { - b = append(b, code.key...) - } - ptr := load(ctxptr, code.headIdx) + code.offset - code = code.next - store(ctxptr, code.idx, ptr) - case opStructFieldOmitEmpty: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) { - code = code.nextField - } else { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldStringTag: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldInt: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyInt: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = append(b, code.key...) - b = appendInt(b, u64, code) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagInt: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldIntPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = appendInt(b, ptrToUint64(p), code) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = append(b, code.key...) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldUint: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyUint: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = append(b, code.key...) - b = appendUint(b, u64, code) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagUint: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldUintPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = appendUint(b, ptrToUint64(p), code) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = append(b, code.key...) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldFloat32: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyFloat32: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat32(ptr + code.offset) - if v != 0 { - b = append(b, code.key...) - b = encodeFloat32(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagFloat32: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldFloat32Ptr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = encodeFloat32(b, ptrToFloat32(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = append(b, code.key...) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldFloat64: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if v != 0 { - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.key...) - b = encodeFloat64(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.key...) - b = append(b, '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldFloat64Ptr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = append(b, code.key...) - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, '"') - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldString: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = encodeNoEscapedString(b, ptrToString(ptr+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyString: - ptr := load(ctxptr, code.headIdx) - v := ptrToString(ptr + code.offset) - if v != "" { - b = append(b, code.key...) - b = encodeNoEscapedString(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagString: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - s := ptrToString(ptr + code.offset) - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, s))) - b = encodeComma(b) - code = code.next - case opStructFieldStringPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, ptrToString(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyStringPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = encodeNoEscapedString(b, ptrToString(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagStringPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, ptrToString(p)))) - } - b = encodeComma(b) - code = code.next - case opStructFieldBool: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyBool: - ptr := load(ctxptr, code.headIdx) - v := ptrToBool(ptr + code.offset) - if v { - b = append(b, code.key...) - b = encodeBool(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagBool: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldBoolPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyBoolPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = encodeBool(b, ptrToBool(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagBoolPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldBytes: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - if len(v) > 0 { - b = append(b, code.key...) - b = encodeByteSlice(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - b = append(b, code.key...) - b = encodeByteSlice(b, v) - b = encodeComma(b) - code = code.next - case opStructFieldBytesPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyBytesPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagBytesPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldNumber: - p := load(ctxptr, code.headIdx) - b = append(b, code.key...) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opStructFieldOmitEmptyNumber: - p := load(ctxptr, code.headIdx) - v := ptrToNumber(p + code.offset) - if v != "" { - b = append(b, code.key...) - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldStringTagNumber: - p := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = encodeComma(b) - code = code.next - case opStructFieldNumberPtr: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyNumberPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.key...) - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldStringTagNumberPtr: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldMarshalJSON, opStructFieldStringTagMarshalJSON: - p := load(ctxptr, code.headIdx) - b = append(b, code.key...) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalJSON: - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - code = code.nextField - break - } - b = append(b, code.key...) - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opStructFieldMarshalJSONPtr, opStructFieldStringTagMarshalJSONPtr: - p := load(ctxptr, code.headIdx) - b = append(b, code.key...) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.key...) - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldMarshalText, opStructFieldStringTagMarshalText: - p := load(ctxptr, code.headIdx) - b = append(b, code.key...) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalText: - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - code = code.nextField - break - } - b = append(b, code.key...) - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opStructFieldMarshalTextPtr, opStructFieldStringTagMarshalTextPtr: - p := load(ctxptr, code.headIdx) - b = append(b, code.key...) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.key...) - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldArray, opStructFieldStringTagArray: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyArray: - p := load(ctxptr, code.headIdx) - p += code.offset - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldArrayPtr, opStructFieldStringTagArrayPtr: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyArrayPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldSlice, opStructFieldStringTagSlice: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptySlice: - p := load(ctxptr, code.headIdx) - p += code.offset - slice := ptrToSlice(p) - if p == 0 || slice.data == nil { - code = code.nextField - } else { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldSlicePtr, opStructFieldStringTagSlicePtr: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptySlicePtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldMap, opStructFieldStringTagMap: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyMap: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { - code = code.nextField - } else { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldMapPtr, opStructFieldStringTagMapPtr: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - p = ptrToPtr(p) - } - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyMapPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - p = ptrToPtr(p) - } - if p != 0 { - b = append(b, code.key...) - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldStruct: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructEnd: - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - } else { - b = append(b, '}') - } - b = encodeComma(b) - code = code.next - case opStructAnonymousEnd: - code = code.next - case opStructEndInt: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyInt: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = append(b, code.key...) - b = appendInt(b, u64, code) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagInt: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndIntPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = appendInt(b, ptrToUint64(p), code) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagIntPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndUint: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyUint: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = append(b, code.key...) - b = appendUint(b, u64, code) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagUint: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndUintPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = appendUint(b, ptrToUint64(p), code) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagUintPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndFloat32: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyFloat32: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat32(ptr + code.offset) - if v != 0 { - b = append(b, code.key...) - b = encodeFloat32(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagFloat32: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndFloat32Ptr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = encodeFloat32(b, ptrToFloat32(p)) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagFloat32Ptr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndFloat64: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if v != 0 { - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.key...) - b = encodeFloat64(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.key...) - b = append(b, '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndFloat64Ptr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - b = appendStructEnd(b) - code = code.next - break - } - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagFloat64Ptr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndString: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = encodeNoEscapedString(b, ptrToString(ptr+code.offset)) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyString: - ptr := load(ctxptr, code.headIdx) - v := ptrToString(ptr + code.offset) - if v != "" { - b = append(b, code.key...) - b = encodeNoEscapedString(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagString: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - s := ptrToString(ptr + code.offset) - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, s))) - b = appendStructEnd(b) - code = code.next - case opStructEndStringPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, ptrToString(p)) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyStringPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = encodeNoEscapedString(b, ptrToString(p)) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagStringPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToString(p) - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, v))) - } - b = appendStructEnd(b) - code = code.next - case opStructEndBool: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyBool: - ptr := load(ctxptr, code.headIdx) - v := ptrToBool(ptr + code.offset) - if v { - b = append(b, code.key...) - b = encodeBool(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagBool: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndBoolPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyBoolPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.key...) - b = encodeBool(b, ptrToBool(p)) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagBoolPtr: - b = append(b, code.key...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndBytes: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - if len(v) > 0 { - b = append(b, code.key...) - b = encodeByteSlice(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - b = append(b, code.key...) - b = encodeByteSlice(b, v) - b = appendStructEnd(b) - code = code.next - case opStructEndNumber: - p := load(ctxptr, code.headIdx) - b = append(b, code.key...) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = appendStructEnd(bb) - code = code.next - case opStructEndOmitEmptyNumber: - p := load(ctxptr, code.headIdx) - v := ptrToNumber(p + code.offset) - if v != "" { - b = append(b, code.key...) - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = appendStructEnd(bb) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagNumber: - p := load(ctxptr, code.headIdx) - b = append(b, code.key...) - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndNumberPtr: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyNumberPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.key...) - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = appendStructEnd(bb) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagNumberPtr: - b = append(b, code.key...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = appendStructEnd(b) - code = code.next - case opEnd: - goto END - } - } -END: - return b, nil -} diff --git a/encode_vm_escaped.go b/encode_vm_escaped.go deleted file mode 100644 index 81dfc77..0000000 --- a/encode_vm_escaped.go +++ /dev/null @@ -1,4091 +0,0 @@ -package json - -import ( - "fmt" - "math" - "reflect" - "sort" - "strings" - "unsafe" -) - -func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt EncodeOption) ([]byte, error) { - recursiveLevel := 0 - ptrOffset := uintptr(0) - ctxptr := ctx.ptr() - code := codeSet.code - - for { - switch code.op { - default: - return nil, fmt.Errorf("encoder (escaped): opcode %s has not been implemented", code.op) - case opPtr: - ptr := load(ctxptr, code.idx) - code = code.next - store(ctxptr, code.idx, ptrToPtr(ptr)) - case opInt: - b = appendInt(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = encodeComma(b) - code = code.next - case opUint: - b = appendUint(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = encodeComma(b) - code = code.next - case opIntString: - b = append(b, '"') - b = appendInt(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opUintString: - b = append(b, '"') - b = appendUint(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opFloat32: - b = encodeFloat32(b, ptrToFloat32(load(ctxptr, code.idx))) - b = encodeComma(b) - code = code.next - case opFloat64: - v := ptrToFloat64(load(ctxptr, code.idx)) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - case opString: - b = encodeEscapedString(b, ptrToString(load(ctxptr, code.idx))) - b = encodeComma(b) - code = code.next - case opBool: - b = encodeBool(b, ptrToBool(load(ctxptr, code.idx))) - b = encodeComma(b) - code = code.next - case opBytes: - ptr := load(ctxptr, code.idx) - slice := ptrToSlice(ptr) - if ptr == 0 || uintptr(slice.data) == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(ptr)) - } - b = encodeComma(b) - code = code.next - case opNumber: - bb, err := encodeNumber(b, ptrToNumber(load(ctxptr, code.idx))) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opInterfacePtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opInterface: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - for _, seen := range ctx.seenPtr { - if ptr == seen { - return nil, errUnsupportedValue(code, ptr) - } - } - ctx.seenPtr = append(ctx.seenPtr, ptr) - iface := (*emptyInterface)(ptrToUnsafePtr(ptr)) - if iface == nil || iface.ptr == nil { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := encodeCompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) - if err != nil { - return nil, err - } - - totalLength := uintptr(codeSet.codeLength) - nextTotalLength := uintptr(ifaceCodeSet.codeLength) - - curlen := uintptr(len(ctx.ptrs)) - offsetNum := ptrOffset / uintptrSize - - newLen := offsetNum + totalLength + nextTotalLength - if curlen < newLen { - ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...) - } - oldPtrs := ctx.ptrs - - newPtrs := ctx.ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] - newPtrs[0] = uintptr(iface.ptr) - - ctx.ptrs = newPtrs - - bb, err := encodeRunEscaped(ctx, b, ifaceCodeSet, opt) - if err != nil { - return nil, err - } - - ctx.ptrs = oldPtrs - ctxptr = ctx.ptr() - ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1] - - b = bb - code = code.next - case opMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - b = append(b, `""`...) - b = encodeComma(b) - code = code.next - break - } - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opSlice: - p := load(ctxptr, code.idx) - slice := ptrToSlice(p) - if p == 0 || slice.data == nil { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.elemIdx, 0) - store(ctxptr, code.length, uintptr(slice.len)) - store(ctxptr, code.idx, uintptr(slice.data)) - if slice.len > 0 { - b = append(b, '[') - code = code.next - store(ctxptr, code.idx, uintptr(slice.data)) - } else { - b = append(b, '[', ']', ',') - code = code.end.next - } - case opSliceElem: - idx := load(ctxptr, code.elemIdx) - length := load(ctxptr, code.length) - idx++ - if idx < length { - store(ctxptr, code.elemIdx, idx) - data := load(ctxptr, code.headIdx) - size := code.size - code = code.next - store(ctxptr, code.idx, data+idx*size) - } else { - last := len(b) - 1 - b[last] = ']' - b = encodeComma(b) - code = code.end.next - } - case opArray: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - } else { - if code.length > 0 { - b = append(b, '[') - store(ctxptr, code.elemIdx, 0) - code = code.next - store(ctxptr, code.idx, p) - } else { - b = append(b, '[', ']', ',') - code = code.end.next - } - } - case opArrayElem: - idx := load(ctxptr, code.elemIdx) - idx++ - if idx < code.length { - store(ctxptr, code.elemIdx, idx) - p := load(ctxptr, code.headIdx) - size := code.size - code = code.next - store(ctxptr, code.idx, p+idx*size) - } else { - last := len(b) - 1 - b[last] = ']' - b = encodeComma(b) - code = code.end.next - } - case opMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opMap: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - uptr := ptrToUnsafePtr(p) - mlen := maplen(uptr) - if mlen > 0 { - b = append(b, '{') - iter := mapiterinit(code.typ, uptr) - ctx.keepRefs = append(ctx.keepRefs, iter) - store(ctxptr, code.elemIdx, 0) - store(ctxptr, code.length, uintptr(mlen)) - store(ctxptr, code.mapIter, uintptr(iter)) - if (opt & EncodeOptionUnorderedMap) == 0 { - mapCtx := newMapContext(mlen) - mapCtx.pos = append(mapCtx.pos, len(b)) - ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx)) - store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx))) - } - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - b = append(b, '{', '}', ',') - code = code.end.next - } - case opMapKey: - idx := load(ctxptr, code.elemIdx) - length := load(ctxptr, code.length) - idx++ - if (opt & EncodeOptionUnorderedMap) != 0 { - if idx < length { - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - store(ctxptr, code.elemIdx, idx) - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - last := len(b) - 1 - b[last] = '}' - b = encodeComma(b) - code = code.end.next - } - } else { - ptr := load(ctxptr, code.end.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - mapCtx.pos = append(mapCtx.pos, len(b)) - if idx < length { - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - store(ctxptr, code.elemIdx, idx) - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - code = code.end - } - } - case opMapValue: - if (opt & EncodeOptionUnorderedMap) != 0 { - last := len(b) - 1 - b[last] = ':' - } else { - ptr := load(ctxptr, code.end.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - mapCtx.pos = append(mapCtx.pos, len(b)) - } - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - value := mapitervalue(iter) - store(ctxptr, code.next.idx, uintptr(value)) - mapiternext(iter) - code = code.next - case opMapEnd: - // this operation only used by sorted map. - length := int(load(ctxptr, code.length)) - ptr := load(ctxptr, code.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - pos := mapCtx.pos - for i := 0; i < length; i++ { - startKey := pos[i*2] - startValue := pos[i*2+1] - var endValue int - if i+1 < length { - endValue = pos[i*2+2] - } else { - endValue = len(b) - } - mapCtx.slice.items = append(mapCtx.slice.items, mapItem{ - key: b[startKey:startValue], - value: b[startValue:endValue], - }) - } - sort.Sort(mapCtx.slice) - buf := mapCtx.buf - for _, item := range mapCtx.slice.items { - buf = append(buf, item.key...) - buf[len(buf)-1] = ':' - buf = append(buf, item.value...) - } - buf[len(buf)-1] = '}' - buf = append(buf, ',') - b = b[:pos[0]] - b = append(b, buf...) - mapCtx.buf = buf - releaseMapContext(mapCtx) - code = code.next - case opStructFieldRecursivePtr: - p := load(ctxptr, code.idx) - if p == 0 { - code = code.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldRecursive: - ptr := load(ctxptr, code.idx) - if ptr != 0 { - if recursiveLevel > startDetectingCyclesAfter { - for _, seen := range ctx.seenPtr { - if ptr == seen { - return nil, errUnsupportedValue(code, ptr) - } - } - } - } - ctx.seenPtr = append(ctx.seenPtr, ptr) - c := code.jmp.code - curlen := uintptr(len(ctx.ptrs)) - offsetNum := ptrOffset / uintptrSize - oldOffset := ptrOffset - ptrOffset += code.jmp.curLen * uintptrSize - - newLen := offsetNum + code.jmp.curLen + code.jmp.nextLen - if curlen < newLen { - ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...) - } - ctxptr = ctx.ptr() + ptrOffset // assign new ctxptr - - store(ctxptr, c.idx, ptr) - store(ctxptr, c.end.next.idx, oldOffset) - store(ctxptr, c.end.next.elemIdx, uintptr(unsafe.Pointer(code.next))) - code = c - recursiveLevel++ - case opStructFieldRecursiveEnd: - recursiveLevel-- - - // restore ctxptr - offset := load(ctxptr, code.idx) - ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1] - - codePtr := load(ctxptr, code.elemIdx) - code = (*opcode)(ptrToUnsafePtr(codePtr)) - ctxptr = ctx.ptr() + offset - ptrOffset = offset - case opStructFieldPtrHead: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHead: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if !code.anonymousKey { - b = append(b, code.escapedKey...) - } - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmpty: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmpty: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - p += code.offset - if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadStringTag: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTag: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - p += code.offset - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadInt: - if code.indirect { - p := load(ctxptr, code.idx) - for i := 0; i < code.ptrNum; i++ { - if p == 0 { - break - } - p = ptrToPtr(p) - } - store(ctxptr, code.idx, p) - } - fallthrough - case opStructFieldHeadInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = appendInt(b, ptrToUint64(p+code.offset), code) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - u64 := ptrToUint64(p + code.offset) - v := u64 & code.mask - if v == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - b = appendInt(b, u64, code) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = append(b, '"') - b = appendInt(b, ptrToUint64(p+code.offset), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - b = appendInt(b, ptrToUint64(p), code) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = appendUint(b, ptrToUint64(p+code.offset), code) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - u64 := ptrToUint64(p + code.offset) - v := u64 & code.mask - if v == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - b = appendUint(b, u64, code) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = append(b, '"') - b = appendUint(b, ptrToUint64(p+code.offset), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - b = appendUint(b, ptrToUint64(p), code) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = encodeFloat32(b, ptrToFloat32(p+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToFloat32(p + code.offset) - if v == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - b = encodeFloat32(b, v) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeFloat32(b, ptrToFloat32(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToFloat64(p + code.offset) - if v == 0 { - code = code.nextField - } else { - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.escapedKey...) - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadString: - if code.indirect { - p := load(ctxptr, code.idx) - for i := 0; i < code.ptrNum; i++ { - if p == 0 { - break - } - p = ptrToPtr(p) - } - store(ctxptr, code.idx, p) - } - fallthrough - case opStructFieldHeadString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, ptrToString(p+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToString(p + code.offset) - if v == "" { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, v) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - s := ptrToString(p + code.offset) - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, s))) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, ptrToString(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, ptrToString(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, ptrToString(p)))) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = encodeBool(b, ptrToBool(p+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToBool(p + code.offset) - if v { - b = append(b, code.escapedKey...) - b = encodeBool(b, v) - b = encodeComma(b) - code = code.next - } else { - code = code.nextField - } - case opStructFieldPtrHeadStringTagBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeBool(b, ptrToBool(p+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeBool(b, ptrToBool(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToBytes(p + code.offset) - if v == nil { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeByteSlice(b, ptrToBytes(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldHeadNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opStructFieldPtrHeadOmitEmptyNumber: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - v := ptrToNumber(p + code.offset) - if v == "" { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - } - case opStructFieldPtrHeadStringTagNumber: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldPtrHeadStringTagNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadArray, opStructFieldPtrHeadStringTagArray, - opStructFieldPtrHeadSlice, opStructFieldPtrHeadStringTagSlice: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadArray, opStructFieldHeadStringTagArray, - opStructFieldHeadSlice, opStructFieldHeadStringTagSlice: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptyArray: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyArray: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - p += code.offset - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptySlice: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptySlice: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - p += code.offset - slice := ptrToSlice(p) - if slice.data == nil { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadArrayPtr, opStructFieldPtrHeadStringTagArrayPtr, - opStructFieldPtrHeadSlicePtr, opStructFieldPtrHeadStringTagSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadArrayPtr, opStructFieldHeadStringTagArrayPtr, - opStructFieldHeadSlicePtr, opStructFieldHeadStringTagSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.nextField - } else { - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadOmitEmptyArrayPtr, opStructFieldPtrHeadOmitEmptySlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyArrayPtr, opStructFieldHeadOmitEmptySlicePtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMap, opStructFieldPtrHeadStringTagMap: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMap, opStructFieldHeadStringTagMap: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if p != 0 && code.indirect { - p = ptrToPtr(p + code.offset) - } - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptyMap: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMap: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if p != 0 && code.indirect { - p = ptrToPtr(p + code.offset) - } - if maplen(ptrToUnsafePtr(p)) == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMapPtr, opStructFieldPtrHeadStringTagMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMapPtr, opStructFieldHeadStringTagMapPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.nextField - break - } - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.nextField - } else { - if code.indirect { - p = ptrToPtr(p) - } - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadOmitEmptyMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMapPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if p == 0 { - code = code.nextField - break - } - p = ptrToPtr(p + code.offset) - if p == 0 { - code = code.nextField - } else { - if code.indirect { - p = ptrToPtr(p) - } - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadStringTagMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadStringTagMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadStringTagMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadOmitEmptyMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadOmitEmptyMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - iface := ptrToInterface(code, p) - if code.nilcheck && encodeIsNilForMarshaler(iface) { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - bb, err := encodeMarshalJSON(code, b, iface, true) - if err != nil { - return nil, err - } - b = bb - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalJSONPtr, opStructFieldPtrHeadStringTagMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMarshalJSONPtr, opStructFieldHeadStringTagMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if !code.anonymousHead { - b = append(b, '{') - } - if p == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadStringTagMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadStringTagMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadStringTagMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadOmitEmptyMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadOmitEmptyMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if p == 0 && code.nilcheck { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - b = encodeComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalTextPtr, opStructFieldPtrHeadStringTagMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMarshalTextPtr, opStructFieldHeadStringTagMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{') - } - b = append(b, code.escapedKey...) - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeComma(b) - } - code = code.end.next - break - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if !code.anonymousHead { - b = append(b, '{') - } - if p == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - b = encodeComma(b) - code = code.next - } - case opStructField: - if !code.anonymousKey { - b = append(b, code.escapedKey...) - } - ptr := load(ctxptr, code.headIdx) + code.offset - code = code.next - store(ctxptr, code.idx, ptr) - case opStructFieldOmitEmpty: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldStringTag: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldInt: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyInt: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = append(b, code.escapedKey...) - b = appendInt(b, u64, code) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagInt: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldIntPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = appendInt(b, ptrToUint64(p), code) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = append(b, code.escapedKey...) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldUint: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyUint: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = append(b, code.escapedKey...) - b = appendUint(b, u64, code) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagUint: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldUintPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = appendUint(b, ptrToUint64(p), code) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = append(b, code.escapedKey...) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldFloat32: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyFloat32: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat32(ptr + code.offset) - if v != 0 { - b = append(b, code.escapedKey...) - b = encodeFloat32(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagFloat32: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldFloat32Ptr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeFloat32(b, ptrToFloat32(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = append(b, code.escapedKey...) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldFloat64: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if v != 0 { - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.escapedKey...) - b = encodeFloat64(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldFloat64Ptr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.next - break - } - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = append(b, code.escapedKey...) - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, '"') - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldString: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, ptrToString(ptr+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyString: - ptr := load(ctxptr, code.headIdx) - v := ptrToString(ptr + code.offset) - if v != "" { - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagString: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - s := ptrToString(ptr + code.offset) - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, s))) - b = encodeComma(b) - code = code.next - case opStructFieldStringPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, ptrToString(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyStringPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, ptrToString(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagStringPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, ptrToString(p)))) - } - b = encodeComma(b) - code = code.next - case opStructFieldBool: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyBool: - ptr := load(ctxptr, code.headIdx) - v := ptrToBool(ptr + code.offset) - if v { - b = append(b, code.escapedKey...) - b = encodeBool(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagBool: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = append(b, '"') - b = encodeComma(b) - code = code.next - case opStructFieldBoolPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyBoolPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeBool(b, ptrToBool(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagBoolPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldBytes: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - if len(v) > 0 { - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, v) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, v) - b = encodeComma(b) - code = code.next - case opStructFieldBytesPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyBytesPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeComma(b) - } - code = code.next - case opStructFieldStringTagBytesPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeComma(b) - code = code.next - case opStructFieldNumber: - p := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opStructFieldOmitEmptyNumber: - p := load(ctxptr, code.headIdx) - v := ptrToNumber(p + code.offset) - if v != "" { - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldStringTagNumber: - p := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = encodeComma(b) - code = code.next - case opStructFieldNumberPtr: - b = append(b, code.escapedKey...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyNumberPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldStringTagNumberPtr: - b = append(b, code.escapedKey...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = encodeComma(b) - code = code.next - case opStructFieldMarshalJSON, opStructFieldStringTagMarshalJSON: - p := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalJSON: - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - code = code.nextField - break - } - b = append(b, code.escapedKey...) - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opStructFieldMarshalJSONPtr, opStructFieldStringTagMarshalJSONPtr: - p := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - bb, err := encodeMarshalJSON(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldMarshalText, opStructFieldStringTagMarshalText: - p := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalText: - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - code = code.nextField - break - } - b = append(b, code.escapedKey...) - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = encodeComma(bb) - code = code.next - case opStructFieldMarshalTextPtr, opStructFieldStringTagMarshalTextPtr: - p := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - bb, err := encodeMarshalText(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = encodeComma(bb) - } - code = code.next - case opStructFieldArray, opStructFieldStringTagArray: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyArray: - p := load(ctxptr, code.headIdx) - p += code.offset - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldArrayPtr, opStructFieldStringTagArrayPtr: - b = append(b, code.escapedKey...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyArrayPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldSlice, opStructFieldStringTagSlice: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptySlice: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - slice := ptrToSlice(p) - if p == 0 || uintptr(slice.data) == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldSlicePtr, opStructFieldStringTagSlicePtr: - b = append(b, code.escapedKey...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptySlicePtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldMap, opStructFieldStringTagMap: - b = append(b, code.escapedKey...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyMap: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { - code = code.nextField - } else { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldMapPtr, opStructFieldStringTagMapPtr: - b = append(b, code.escapedKey...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - p = ptrToPtr(p) - } - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyMapPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - p = ptrToPtr(p) - } - if p != 0 { - b = append(b, code.escapedKey...) - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldStruct: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructEnd: - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - } else { - b = append(b, '}') - } - b = encodeComma(b) - code = code.next - case opStructAnonymousEnd: - code = code.next - case opStructEndInt: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyInt: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = append(b, code.escapedKey...) - b = appendInt(b, u64, code) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagInt: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndIntPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = appendInt(b, ptrToUint64(p), code) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagIntPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndUint: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyUint: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = append(b, code.escapedKey...) - b = appendUint(b, u64, code) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagUint: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndUintPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = appendUint(b, ptrToUint64(p), code) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagUintPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndFloat32: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyFloat32: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat32(ptr + code.offset) - if v != 0 { - b = append(b, code.escapedKey...) - b = encodeFloat32(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagFloat32: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndFloat32Ptr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeFloat32(b, ptrToFloat32(p)) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagFloat32Ptr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndFloat64: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if v != 0 { - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.escapedKey...) - b = encodeFloat64(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndFloat64Ptr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - b = appendStructEnd(b) - code = code.next - break - } - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagFloat64Ptr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndString: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, ptrToString(ptr+code.offset)) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyString: - ptr := load(ctxptr, code.headIdx) - v := ptrToString(ptr + code.offset) - if v != "" { - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagString: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - s := ptrToString(ptr + code.offset) - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, s))) - b = appendStructEnd(b) - code = code.next - case opStructEndStringPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, ptrToString(p)) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyStringPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeEscapedString(b, ptrToString(p)) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagStringPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToString(p) - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, v))) - } - b = appendStructEnd(b) - code = code.next - case opStructEndBool: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyBool: - ptr := load(ctxptr, code.headIdx) - v := ptrToBool(ptr + code.offset) - if v { - b = append(b, code.escapedKey...) - b = encodeBool(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagBool: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = append(b, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndBoolPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyBoolPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - b = encodeBool(b, ptrToBool(p)) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagBoolPtr: - b = append(b, code.escapedKey...) - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = appendStructEnd(b) - code = code.next - case opStructEndBytes: - ptr := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - if len(v) > 0 { - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, v) - b = appendStructEnd(b) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - b = append(b, code.escapedKey...) - b = encodeByteSlice(b, v) - b = appendStructEnd(b) - code = code.next - case opStructEndNumber: - p := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = appendStructEnd(bb) - code = code.next - case opStructEndOmitEmptyNumber: - p := load(ctxptr, code.headIdx) - v := ptrToNumber(p + code.offset) - if v != "" { - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = appendStructEnd(bb) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagNumber: - p := load(ctxptr, code.headIdx) - b = append(b, code.escapedKey...) - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = appendStructEnd(b) - code = code.next - case opStructEndNumberPtr: - b = append(b, code.escapedKey...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = appendStructEnd(b) - code = code.next - case opStructEndOmitEmptyNumberPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = appendStructEnd(bb) - } else { - last := len(b) - 1 - if b[last] == ',' { - b[last] = '}' - b = encodeComma(b) - } else { - b = appendStructEnd(b) - } - } - code = code.next - case opStructEndStringTagNumberPtr: - b = append(b, code.escapedKey...) - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = appendStructEnd(b) - code = code.next - case opEnd: - goto END - } - } -END: - return b, nil -} diff --git a/internal/encoder/compiler_race.go b/internal/encoder/compiler_race.go index 827226c..3fecef7 100644 --- a/internal/encoder/compiler_race.go +++ b/internal/encoder/compiler_race.go @@ -11,7 +11,7 @@ import ( var setsMu sync.RWMutex -func CompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) { +func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) { if typeptr > typeAddr.MaxTypeAddr { return compileToGetCodeSetSlowPath(typeptr) } diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index df98923..2836ec2 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -476,3 +476,14 @@ func AppendComma(b []byte) []byte { func AppendStructEnd(b []byte) []byte { return append(b, '}', ',') } + +func IsNilForMarshaler(v interface{}) bool { + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr: + return rv.IsNil() + case reflect.Slice: + return rv.IsNil() || rv.Len() == 0 + } + return false +} diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 5bddff4..ad4154f 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -269,14 +269,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = bb code = code.Next case encoder.OpMarshalJSONPtr: - p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) if p == 0 { b = appendNull(b) b = appendComma(b) code = code.Next break } - store(ctxptr, code.Idx, p) + store(ctxptr, code.Idx, ptrToPtr(p)) fallthrough case encoder.OpMarshalJSON: p := load(ctxptr, code.Idx) @@ -293,14 +293,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendComma(bb) code = code.Next case encoder.OpMarshalTextPtr: - p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + p := load(ctxptr, code.Idx) if p == 0 { b = appendNull(b) b = appendComma(b) code = code.Next break } - store(ctxptr, code.Idx, p) + store(ctxptr, code.Idx, ptrToPtr(p)) fallthrough case encoder.OpMarshalText: p := load(ctxptr, code.Idx) @@ -337,6 +337,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } store(ctxptr, code.ElemIdx, 0) store(ctxptr, code.Length, uintptr(slice.Len)) + store(ctxptr, code.Idx, uintptr(slice.Data)) if slice.Len > 0 { b = append(b, '[') code = code.Next @@ -2815,11 +2816,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p = ptrToPtr(p + code.Offset) } } - if p == 0 && code.Nilcheck { + iface := ptrToInterface(code, p) + if code.Nilcheck && encoder.IsNilForMarshaler(iface) { code = code.NextField } else { b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(code, b, iface, false) if err != nil { return nil, err } diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go new file mode 100644 index 0000000..4bee00f --- /dev/null +++ b/internal/encoder/vm_escaped/vm.go @@ -0,0 +1,4500 @@ +package vm_escaped + +import ( + "fmt" + "math" + "reflect" + "sort" + "strings" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +var ( + load = encoder.Load + store = encoder.Store + loadNPtr = encoder.LoadNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendEscapedString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSON + appendMarshalText = encoder.AppendMarshalText + appendNull = encoder.AppendNull + appendComma = encoder.AppendComma + appendStructEnd = encoder.AppendStructEnd + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + errMarshalerWithCode = encoder.ErrMarshalerWithCode + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + code := codeSet.Code + + for { + switch code.Op { + default: + return nil, fmt.Errorf("encoder: opcode %s has not been implemented", code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpUintPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpFloat32Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpFloat64Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, encoder.ErrUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStringPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpString: + b = appendString(b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBoolPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBool: + b = appendBool(b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBytesPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpNumberPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpInterfacePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(codeSet.CodeLength) + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + oldPtrs := ctx.Ptrs + + newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] + newPtrs[0] = uintptr(iface.ptr) + + ctx.Ptrs = newPtrs + + bb, err := Run(ctx, b, ifaceCodeSet, opt) + if err != nil { + return nil, err + } + + ctx.Ptrs = oldPtrs + ctxptr = ctx.Ptr() + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + b = bb + code = code.Next + case encoder.OpMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpSlicePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + store(ctxptr, code.Idx, uintptr(slice.Data)) + if slice.Len > 0 { + b = append(b, '[') + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = append(b, '[', ']', ',') + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + last := len(b) - 1 + b[last] = ']' + b = appendComma(b) + code = code.End.Next + } + case encoder.OpArrayPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + if code.Length > 0 { + b = append(b, '[') + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = append(b, '[', ']', ',') + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < code.Length { + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + last := len(b) - 1 + b[last] = ']' + b = appendComma(b) + code = code.End.Next + } + case encoder.OpMapPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = append(b, '{', '}', ',') + code = code.End.Next + break + } + b = append(b, '{') + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (opt & encoder.UnorderedMapOption) == 0 { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (opt & encoder.UnorderedMapOption) != 0 { + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + last := len(b) - 1 + b[last] = '}' + b = appendComma(b) + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (opt & encoder.UnorderedMapOption) != 0 { + last := len(b) - 1 + b[last] = ':' + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = append(buf, item.Key...) + buf[len(buf)-1] = ':' + buf = append(buf, item.Value...) + } + buf[len(buf)-1] = '}' + buf = append(buf, ',') + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpStructFieldRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructFieldRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + code = c + recursiveLevel++ + case encoder.OpStructFieldRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if !code.AnonymousKey { + b = append(b, code.EscapedKey...) + } + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + if p == 0 || (ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr")) { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadStringTag: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTag: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + b = appendInt(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + b = appendUint(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat32(p + code.Offset) + if v == 0 { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + b = appendFloat32(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat64(p + code.Offset) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.EscapedKey...) + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToString(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + b = appendString(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.EscapedKey...) + b = appendBool(b, v) + b = appendComma(b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadStringTagBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToBytes(p + code.Offset) + if v == nil { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToNumber(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadStringTagArray, + encoder.OpStructPtrHeadSlice, encoder.OpStructPtrHeadStringTagSlice: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadStringTagArray, + encoder.OpStructHeadSlice, encoder.OpStructHeadStringTagSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + slice := ptrToSlice(p) + if slice.Data == nil { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadStringTagArrayPtr, + encoder.OpStructPtrHeadSlicePtr, encoder.OpStructPtrHeadStringTagSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadStringTagArrayPtr, + encoder.OpStructHeadSlicePtr, encoder.OpStructHeadStringTagSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap, encoder.OpStructPtrHeadStringTagMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMap, encoder.OpStructHeadStringTagMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr, encoder.OpStructPtrHeadStringTagMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMapPtr, encoder.OpStructHeadStringTagMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + iface := ptrToInterface(code, p) + if code.Nilcheck && encoder.IsNilForMarshaler(iface) { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + bb, err := appendMarshalJSON(code, b, iface, true) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr, encoder.OpStructPtrHeadStringTagMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr, encoder.OpStructHeadStringTagMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr, encoder.OpStructPtrHeadStringTagMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalTextPtr, encoder.OpStructHeadStringTagMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.EscapedKey...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructField: + if !code.AnonymousKey { + b = append(b, code.EscapedKey...) + } + p := load(ctxptr, code.HeadIdx) + code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr") { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldStringTag: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.EscapedKey...) + b = appendInt(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldIntPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.EscapedKey...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.EscapedKey...) + b = appendUint(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUintPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.EscapedKey...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = append(b, code.EscapedKey...) + b = appendFloat32(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.EscapedKey...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.EscapedKey...) + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.EscapedKey...) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = append(b, code.EscapedKey...) + b = appendString(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldStringPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagStringPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.EscapedKey...) + b = appendBool(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBoolPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBoolPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytes: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytesPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytesPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumberPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumberPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldMarshalJSON, encoder.OpStructFieldStringTagMarshalJSON: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = append(b, code.EscapedKey...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr, encoder.OpStructFieldStringTagMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText, encoder.OpStructFieldStringTagMarshalText: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = append(b, code.EscapedKey...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr, encoder.OpStructFieldStringTagMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldArray, encoder.OpStructFieldStringTagArray: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr, encoder.OpStructFieldStringTagArrayPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice, encoder.OpStructFieldStringTagSlice: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr, encoder.OpStructFieldStringTagSlicePtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap, encoder.OpStructFieldStringTagMap: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum+1) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum+1) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr, encoder.OpStructFieldStringTagMapPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructEnd: + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + } else { + b = append(b, '}') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEndInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.EscapedKey...) + b = appendInt(b, u64, code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndIntPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendInt(b, ptrToUint64(p), code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagIntPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.EscapedKey...) + b = appendUint(b, u64, code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndUintPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendUint(b, ptrToUint64(p), code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagUintPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = append(b, code.EscapedKey...) + b = appendFloat32(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat32Ptr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat64: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.EscapedKey...) + b = appendFloat64(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendStructEnd(b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat64Ptr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = append(b, code.EscapedKey...) + b = appendString(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndStringPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendString(b, ptrToString(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagStringPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToString(p) + b = appendString(b, string(appendString([]byte{}, v))) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.EscapedKey...) + b = appendBool(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBoolPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendBool(b, ptrToBool(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBoolPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBytes: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBytesPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBytesPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.EscapedKey...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndNumberPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagNumberPtr: + b = append(b, code.EscapedKey...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} From 9cbe7b39917dd844cf6a0f78d21a93daf2529d3d Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 15:46:55 +0900 Subject: [PATCH 07/15] Move encoder source to internal package --- encode.go | 299 +- encode_vm_escaped_indent.go | 4531 -------------------- encode_vm_indent.go | 4532 -------------------- internal/encoder/encoder.go | 79 + internal/encoder/indent.go | 112 + internal/encoder/vm/vm.go | 8 +- internal/encoder/vm_escaped/vm.go | 6 +- internal/encoder/vm_escaped_indent/vm.go | 4993 ++++++++++++++++++++++ internal/encoder/vm_indent/vm.go | 4993 ++++++++++++++++++++++ 9 files changed, 10213 insertions(+), 9340 deletions(-) delete mode 100644 encode_vm_escaped_indent.go delete mode 100644 encode_vm_indent.go create mode 100644 internal/encoder/indent.go create mode 100644 internal/encoder/vm_escaped_indent/vm.go create mode 100644 internal/encoder/vm_indent/vm.go diff --git a/encode.go b/encode.go index 9aee645..4dfdd2c 100644 --- a/encode.go +++ b/encode.go @@ -1,21 +1,15 @@ package json import ( - "bytes" - "encoding" - "encoding/base64" - "fmt" "io" - "math" - "reflect" - "strconv" - "strings" "sync" "unsafe" "github.com/goccy/go-json/internal/encoder" "github.com/goccy/go-json/internal/encoder/vm" "github.com/goccy/go-json/internal/encoder/vm_escaped" + "github.com/goccy/go-json/internal/encoder/vm_escaped_indent" + "github.com/goccy/go-json/internal/encoder/vm_indent" ) // An Encoder writes JSON values to an output stream. @@ -41,15 +35,6 @@ const ( var ( encRuntimeContextPool = sync.Pool{ - New: func() interface{} { - return &encodeRuntimeContext{ - buf: make([]byte, 0, bufSize), - ptrs: make([]uintptr, 128), - keepRefs: make([]unsafe.Pointer, 0, 8), - } - }, - } - encRuntimeContextPool2 = sync.Pool{ New: func() interface{} { return &encoder.RuntimeContext{ Buf: make([]byte, 0, bufSize), @@ -60,22 +45,14 @@ var ( } ) -func takeEncodeRuntimeContext() *encodeRuntimeContext { - return encRuntimeContextPool.Get().(*encodeRuntimeContext) +func takeEncodeRuntimeContext() *encoder.RuntimeContext { + return encRuntimeContextPool.Get().(*encoder.RuntimeContext) } -func releaseEncodeRuntimeContext(ctx *encodeRuntimeContext) { +func releaseEncodeRuntimeContext(ctx *encoder.RuntimeContext) { encRuntimeContextPool.Put(ctx) } -func takeEncodeRuntimeContext2() *encoder.RuntimeContext { - return encRuntimeContextPool2.Get().(*encoder.RuntimeContext) -} - -func releaseEncodeRuntimeContext2(ctx *encoder.RuntimeContext) { - encRuntimeContextPool2.Put(ctx) -} - // NewEncoder returns a new encoder that writes to w. func NewEncoder(w io.Writer) *Encoder { return &Encoder{w: w, enabledHTMLEscape: true} @@ -98,7 +75,7 @@ func (e *Encoder) EncodeWithOption(v interface{}, optFuncs ...EncodeOptionFunc) return err } -func (e *Encoder) encodeWithOption(ctx *encodeRuntimeContext, v interface{}, optFuncs ...EncodeOptionFunc) error { +func (e *Encoder) encodeWithOption(ctx *encoder.RuntimeContext, v interface{}, optFuncs ...EncodeOptionFunc) error { var opt EncodeOption if e.enabledHTMLEscape { opt |= EncodeOptionHTMLEscape @@ -113,9 +90,7 @@ func (e *Encoder) encodeWithOption(ctx *encodeRuntimeContext, v interface{}, opt if e.enabledIndent { buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr, opt) } else { - ctx := takeEncodeRuntimeContext2() buf, err = encode(ctx, v, opt) - releaseEncodeRuntimeContext2(ctx) } if err != nil { return err @@ -153,11 +128,11 @@ func (e *Encoder) SetIndent(prefix, indent string) { } func marshal(v interface{}, opt EncodeOption) ([]byte, error) { - ctx := takeEncodeRuntimeContext2() + ctx := takeEncodeRuntimeContext() buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape) if err != nil { - releaseEncodeRuntimeContext2(ctx) + releaseEncodeRuntimeContext(ctx) return nil, err } @@ -169,16 +144,16 @@ func marshal(v interface{}, opt EncodeOption) ([]byte, error) { copied := make([]byte, len(buf)) copy(copied, buf) - releaseEncodeRuntimeContext2(ctx) + releaseEncodeRuntimeContext(ctx) return copied, nil } func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) { - ctx := takeEncodeRuntimeContext2() + ctx := takeEncodeRuntimeContext() buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape) if err != nil { - releaseEncodeRuntimeContext2(ctx) + releaseEncodeRuntimeContext(ctx) return nil, err } @@ -190,7 +165,7 @@ func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) { copied := make([]byte, len(buf)) copy(copied, buf) - releaseEncodeRuntimeContext2(ctx) + releaseEncodeRuntimeContext(ctx) return copied, nil } @@ -214,8 +189,8 @@ func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]by func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { b := ctx.Buf[:0] if v == nil { - b = encodeNull(b) - b = encodeComma(b) + b = encoder.AppendNull(b) + b = encoder.AppendComma(b) return b, nil } header := (*emptyInterface)(unsafe.Pointer(&v)) @@ -242,8 +217,8 @@ func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byt func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { b := ctx.Buf[:0] if v == nil { - b = encodeNull(b) - b = encodeComma(b) + b = encoder.AppendNull(b) + b = encoder.AppendComma(b) return b, nil } header := (*emptyInterface)(unsafe.Pointer(&v)) @@ -266,33 +241,33 @@ func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption return buf, nil } -func encodeIndent(ctx *encodeRuntimeContext, v interface{}, prefix, indent string, opt EncodeOption) ([]byte, error) { - b := ctx.buf[:0] +func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent string, opt EncodeOption) ([]byte, error) { + b := ctx.Buf[:0] if v == nil { - b = encodeNull(b) - b = encodeIndentComma(b) + b = encoder.AppendNull(b) + b = encoder.AppendCommaIndent(b) return b, nil } header := (*emptyInterface)(unsafe.Pointer(&v)) typ := header.typ typeptr := uintptr(unsafe.Pointer(typ)) - codeSet, err := encodeCompileToGetCodeSet(typeptr) + codeSet, err := encoder.CompileToGetCodeSet(typeptr) if err != nil { return nil, err } p := uintptr(header.ptr) - ctx.init(p, codeSet.codeLength) + ctx.Init(p, codeSet.CodeLength) buf, err := encodeRunIndentCode(ctx, b, codeSet, prefix, indent, opt) - ctx.keepRefs = append(ctx.keepRefs, header.ptr) + ctx.KeepRefs = append(ctx.KeepRefs, header.ptr) if err != nil { return nil, err } - ctx.buf = buf + ctx.Buf = buf return buf, nil } @@ -303,227 +278,11 @@ func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.Opcod return vm.Run(ctx, b, codeSet, encoder.Option(opt)) } -func encodeRunIndentCode(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, prefix, indent string, opt EncodeOption) ([]byte, error) { - ctx.prefix = []byte(prefix) - ctx.indentStr = []byte(indent) +func encodeRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, prefix, indent string, opt EncodeOption) ([]byte, error) { + ctx.Prefix = []byte(prefix) + ctx.IndentStr = []byte(indent) if (opt & EncodeOptionHTMLEscape) != 0 { - return encodeRunEscapedIndent(ctx, b, codeSet, opt) + return vm_escaped_indent.Run(ctx, b, codeSet, encoder.Option(opt)) } - return encodeRunIndent(ctx, b, codeSet, opt) -} - -func encodeFloat32(b []byte, v float32) []byte { - f64 := float64(v) - abs := math.Abs(f64) - fmt := byte('f') - // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. - if abs != 0 { - f32 := float32(abs) - if f32 < 1e-6 || f32 >= 1e21 { - fmt = 'e' - } - } - return strconv.AppendFloat(b, f64, fmt, -1, 32) -} - -func encodeFloat64(b []byte, v float64) []byte { - abs := math.Abs(v) - fmt := byte('f') - // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. - if abs != 0 { - if abs < 1e-6 || abs >= 1e21 { - fmt = 'e' - } - } - return strconv.AppendFloat(b, v, fmt, -1, 64) -} - -func encodeBool(b []byte, v bool) []byte { - if v { - return append(b, "true"...) - } - return append(b, "false"...) -} - -func encodeNull(b []byte) []byte { - return append(b, "null"...) -} - -func encodeComma(b []byte) []byte { - return append(b, ',') -} - -func encodeIndentComma(b []byte) []byte { - return append(b, ',', '\n') -} - -func appendStructEnd(b []byte) []byte { - return append(b, '}', ',') -} - -func appendStructEndIndent(ctx *encodeRuntimeContext, b []byte, indent int) []byte { - b = append(b, '\n') - b = append(b, ctx.prefix...) - b = append(b, bytes.Repeat(ctx.indentStr, ctx.baseIndent+indent)...) - return append(b, '}', ',', '\n') -} - -func encodeByteSlice(b []byte, src []byte) []byte { - encodedLen := base64.StdEncoding.EncodedLen(len(src)) - b = append(b, '"') - pos := len(b) - remainLen := cap(b[pos:]) - var buf []byte - if remainLen > encodedLen { - buf = b[pos : pos+encodedLen] - } else { - buf = make([]byte, encodedLen) - } - base64.StdEncoding.Encode(buf, src) - return append(append(b, buf...), '"') -} - -func encodeNumber(b []byte, n Number) ([]byte, error) { - if len(n) == 0 { - return append(b, '0'), nil - } - for i := 0; i < len(n); i++ { - if !floatTable[n[i]] { - return nil, fmt.Errorf("json: invalid number literal %q", n) - } - } - b = append(b, n...) - return b, nil -} - -func appendIndent(ctx *encodeRuntimeContext, b []byte, indent int) []byte { - b = append(b, ctx.prefix...) - return append(b, bytes.Repeat(ctx.indentStr, ctx.baseIndent+indent)...) -} - -func encodeIsNilForMarshaler(v interface{}) bool { - rv := reflect.ValueOf(v) - switch rv.Kind() { - case reflect.Interface, reflect.Map, reflect.Ptr: - return rv.IsNil() - case reflect.Slice: - return rv.IsNil() || rv.Len() == 0 - } - return false -} - -func encodeMarshalJSON(code *opcode, b []byte, v interface{}, escape bool) ([]byte, error) { - rv := reflect.ValueOf(v) // convert by dynamic interface type - if code.addrForMarshaler { - if rv.CanAddr() { - rv = rv.Addr() - } else { - newV := reflect.New(rv.Type()) - newV.Elem().Set(rv) - rv = newV - } - } - v = rv.Interface() - marshaler, ok := v.(Marshaler) - if !ok { - return encodeNull(b), nil - } - bb, err := marshaler.MarshalJSON() - if err != nil { - return nil, &MarshalerError{Type: reflect.TypeOf(v), Err: err} - } - buf := bytes.NewBuffer(b) - //TODO: we should validate buffer with `compact` - if err := compact(buf, bb, escape); err != nil { - return nil, &MarshalerError{Type: reflect.TypeOf(v), Err: err} - } - return buf.Bytes(), nil -} - -func encodeMarshalJSONIndent(ctx *encodeRuntimeContext, code *opcode, b []byte, v interface{}, indent int, escape bool) ([]byte, error) { - rv := reflect.ValueOf(v) // convert by dynamic interface type - if code.addrForMarshaler { - if rv.CanAddr() { - rv = rv.Addr() - } else { - newV := reflect.New(rv.Type()) - newV.Elem().Set(rv) - rv = newV - } - } - v = rv.Interface() - marshaler, ok := v.(Marshaler) - if !ok { - return encodeNull(b), nil - } - bb, err := marshaler.MarshalJSON() - if err != nil { - return nil, &MarshalerError{Type: reflect.TypeOf(v), Err: err} - } - var compactBuf bytes.Buffer - if err := compact(&compactBuf, bb, escape); err != nil { - return nil, &MarshalerError{Type: reflect.TypeOf(v), Err: err} - } - var indentBuf bytes.Buffer - if err := encodeWithIndent( - &indentBuf, - compactBuf.Bytes(), - string(ctx.prefix)+strings.Repeat(string(ctx.indentStr), ctx.baseIndent+indent+1), - string(ctx.indentStr), - ); err != nil { - return nil, &MarshalerError{Type: reflect.TypeOf(v), Err: err} - } - return append(b, indentBuf.Bytes()...), nil -} - -func encodeMarshalText(code *opcode, b []byte, v interface{}, escape bool) ([]byte, error) { - rv := reflect.ValueOf(v) // convert by dynamic interface type - if code.addrForMarshaler { - if rv.CanAddr() { - rv = rv.Addr() - } else { - newV := reflect.New(rv.Type()) - newV.Elem().Set(rv) - rv = newV - } - } - v = rv.Interface() - marshaler, ok := v.(encoding.TextMarshaler) - if !ok { - return encodeNull(b), nil - } - bytes, err := marshaler.MarshalText() - if err != nil { - return nil, &MarshalerError{Type: reflect.TypeOf(v), Err: err} - } - if escape { - return encodeEscapedString(b, *(*string)(unsafe.Pointer(&bytes))), nil - } - return encodeNoEscapedString(b, *(*string)(unsafe.Pointer(&bytes))), nil -} - -func encodeMarshalTextIndent(code *opcode, b []byte, v interface{}, escape bool) ([]byte, error) { - rv := reflect.ValueOf(v) // convert by dynamic interface type - if code.addrForMarshaler { - if rv.CanAddr() { - rv = rv.Addr() - } else { - newV := reflect.New(rv.Type()) - newV.Elem().Set(rv) - rv = newV - } - } - v = rv.Interface() - marshaler, ok := v.(encoding.TextMarshaler) - if !ok { - return encodeNull(b), nil - } - bytes, err := marshaler.MarshalText() - if err != nil { - return nil, &MarshalerError{Type: reflect.TypeOf(v), Err: err} - } - if escape { - return encodeEscapedString(b, *(*string)(unsafe.Pointer(&bytes))), nil - } - return encodeNoEscapedString(b, *(*string)(unsafe.Pointer(&bytes))), nil + return vm_indent.Run(ctx, b, codeSet, encoder.Option(opt)) } diff --git a/encode_vm_escaped_indent.go b/encode_vm_escaped_indent.go deleted file mode 100644 index 3e31da6..0000000 --- a/encode_vm_escaped_indent.go +++ /dev/null @@ -1,4531 +0,0 @@ -package json - -import ( - "bytes" - "fmt" - "math" - "reflect" - "sort" - "strings" - "unsafe" -) - -func encodeRunEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt EncodeOption) ([]byte, error) { - recursiveLevel := 0 - ptrOffset := uintptr(0) - ctxptr := ctx.ptr() - code := codeSet.code - - for { - switch code.op { - default: - return nil, fmt.Errorf("encoder (escaped+indent): opcode %s has not been implemented", code.op) - case opPtr: - ptr := load(ctxptr, code.idx) - code = code.next - store(ctxptr, code.idx, ptrToPtr(ptr)) - case opInt: - b = appendInt(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = encodeIndentComma(b) - code = code.next - case opUint: - b = appendUint(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = encodeIndentComma(b) - code = code.next - case opIntString: - b = append(b, '"') - b = appendInt(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opUintString: - b = append(b, '"') - b = appendUint(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opFloat32: - b = encodeFloat32(b, ptrToFloat32(load(ctxptr, code.idx))) - b = encodeIndentComma(b) - code = code.next - case opFloat64: - v := ptrToFloat64(load(ctxptr, code.idx)) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - code = code.next - case opString: - b = encodeEscapedString(b, ptrToString(load(ctxptr, code.idx))) - b = encodeIndentComma(b) - code = code.next - case opBool: - b = encodeBool(b, ptrToBool(load(ctxptr, code.idx))) - b = encodeIndentComma(b) - code = code.next - case opBytes: - p := load(ctxptr, code.idx) - slice := ptrToSlice(p) - if p == 0 || slice.data == nil { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeIndentComma(b) - code = code.next - case opNumber: - bb, err := encodeNumber(b, ptrToNumber(load(ctxptr, code.idx))) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opInterface: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.next - break - } - for _, seen := range ctx.seenPtr { - if ptr == seen { - return nil, errUnsupportedValue(code, ptr) - } - } - ctx.seenPtr = append(ctx.seenPtr, ptr) - iface := (*emptyInterface)(ptrToUnsafePtr(ptr)) - if iface == nil || iface.ptr == nil { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.next - break - } - ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := encodeCompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) - if err != nil { - return nil, err - } - - totalLength := uintptr(codeSet.codeLength) - nextTotalLength := uintptr(ifaceCodeSet.codeLength) - - curlen := uintptr(len(ctx.ptrs)) - offsetNum := ptrOffset / uintptrSize - - newLen := offsetNum + totalLength + nextTotalLength - if curlen < newLen { - ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...) - } - oldPtrs := ctx.ptrs - - newPtrs := ctx.ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] - newPtrs[0] = uintptr(iface.ptr) - - ctx.ptrs = newPtrs - - oldBaseIndent := ctx.baseIndent - ctx.baseIndent = code.indent - bb, err := encodeRunEscapedIndent(ctx, b, ifaceCodeSet, opt) - if err != nil { - return nil, err - } - ctx.baseIndent = oldBaseIndent - - ctx.ptrs = oldPtrs - ctxptr = ctx.ptr() - ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1] - - b = bb - code = code.next - case opMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.next - break - } - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opMarshalText: - 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) - slice := ptrToSlice(p) - if p == 0 || slice.data == nil { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.end.next - } else { - store(ctxptr, code.elemIdx, 0) - store(ctxptr, code.length, uintptr(slice.len)) - store(ctxptr, code.idx, uintptr(slice.data)) - if slice.len > 0 { - b = append(b, '[', '\n') - b = appendIndent(ctx, b, code.indent+1) - code = code.next - store(ctxptr, code.idx, uintptr(slice.data)) - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, '[', ']', ',', '\n') - code = code.end.next - } - } - case opSliceElem: - idx := load(ctxptr, code.elemIdx) - length := load(ctxptr, code.length) - idx++ - if idx < length { - b = appendIndent(ctx, b, code.indent+1) - store(ctxptr, code.elemIdx, idx) - data := load(ctxptr, code.headIdx) - size := code.size - code = code.next - store(ctxptr, code.idx, data+idx*size) - } else { - b = b[:len(b)-2] - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent) - b = append(b, ']', ',', '\n') - code = code.end.next - } - case opArray: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.end.next - } else { - if code.length > 0 { - b = append(b, '[', '\n') - b = appendIndent(ctx, b, code.indent+1) - store(ctxptr, code.elemIdx, 0) - code = code.next - store(ctxptr, code.idx, p) - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, '[', ']', ',', '\n') - code = code.end.next - } - } - case opArrayElem: - idx := load(ctxptr, code.elemIdx) - idx++ - if idx < code.length { - b = appendIndent(ctx, b, code.indent+1) - store(ctxptr, code.elemIdx, idx) - p := load(ctxptr, code.headIdx) - size := code.size - code = code.next - store(ctxptr, code.idx, p+idx*size) - } else { - b = b[:len(b)-2] - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent) - b = append(b, ']', ',', '\n') - code = code.end.next - } - case opMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opMap: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.end.next - } else { - uptr := ptrToUnsafePtr(ptr) - mlen := maplen(uptr) - if mlen > 0 { - b = append(b, '{', '\n') - iter := mapiterinit(code.typ, uptr) - ctx.keepRefs = append(ctx.keepRefs, iter) - store(ctxptr, code.elemIdx, 0) - store(ctxptr, code.length, uintptr(mlen)) - store(ctxptr, code.mapIter, uintptr(iter)) - - if (opt & EncodeOptionUnorderedMap) == 0 { - mapCtx := newMapContext(mlen) - mapCtx.pos = append(mapCtx.pos, len(b)) - ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx)) - store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx))) - } else { - b = appendIndent(ctx, b, code.next.indent) - } - - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - b = append(b, '{', '}', ',', '\n') - code = code.end.next - } - } - case opMapKey: - idx := load(ctxptr, code.elemIdx) - length := load(ctxptr, code.length) - idx++ - if (opt & EncodeOptionUnorderedMap) != 0 { - if idx < length { - b = appendIndent(ctx, b, code.indent) - store(ctxptr, code.elemIdx, idx) - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - last := len(b) - 1 - b[last] = '\n' - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}', ',', '\n') - code = code.end.next - } - } else { - ptr := load(ctxptr, code.end.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - mapCtx.pos = append(mapCtx.pos, len(b)) - if idx < length { - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - store(ctxptr, code.elemIdx, idx) - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - code = code.end - } - } - case opMapValue: - if (opt & EncodeOptionUnorderedMap) != 0 { - b = append(b, ':', ' ') - } else { - ptr := load(ctxptr, code.end.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - mapCtx.pos = append(mapCtx.pos, len(b)) - } - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - value := mapitervalue(iter) - store(ctxptr, code.next.idx, uintptr(value)) - mapiternext(iter) - code = code.next - case opMapEnd: - // this operation only used by sorted map - length := int(load(ctxptr, code.length)) - ptr := load(ctxptr, code.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - pos := mapCtx.pos - for i := 0; i < length; i++ { - startKey := pos[i*2] - startValue := pos[i*2+1] - var endValue int - if i+1 < length { - endValue = pos[i*2+2] - } else { - endValue = len(b) - } - mapCtx.slice.items = append(mapCtx.slice.items, mapItem{ - key: b[startKey:startValue], - value: b[startValue:endValue], - }) - } - sort.Sort(mapCtx.slice) - buf := mapCtx.buf - for _, item := range mapCtx.slice.items { - buf = append(buf, ctx.prefix...) - buf = append(buf, bytes.Repeat(ctx.indentStr, ctx.baseIndent+code.indent+1)...) - buf = append(buf, item.key...) - buf[len(buf)-2] = ':' - buf[len(buf)-1] = ' ' - buf = append(buf, item.value...) - } - buf = buf[:len(buf)-2] - buf = append(buf, '\n') - buf = append(buf, ctx.prefix...) - buf = append(buf, bytes.Repeat(ctx.indentStr, ctx.baseIndent+code.indent)...) - buf = append(buf, '}', ',', '\n') - - b = b[:pos[0]] - b = append(b, buf...) - mapCtx.buf = buf - releaseMapContext(mapCtx) - code = code.next - case opStructFieldPtrHeadRecursive: - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - case opStructFieldRecursive: - ptr := load(ctxptr, code.idx) - if ptr != 0 { - if recursiveLevel > startDetectingCyclesAfter { - for _, seen := range ctx.seenPtr { - if ptr == seen { - return nil, errUnsupportedValue(code, ptr) - } - } - } - } - ctx.seenPtr = append(ctx.seenPtr, ptr) - c := code.jmp.code - curlen := uintptr(len(ctx.ptrs)) - offsetNum := ptrOffset / uintptrSize - oldOffset := ptrOffset - ptrOffset += code.jmp.curLen * uintptrSize - - newLen := offsetNum + code.jmp.curLen + code.jmp.nextLen - if curlen < newLen { - ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...) - } - ctxptr = ctx.ptr() + ptrOffset // assign new ctxptr - - store(ctxptr, c.idx, ptr) - store(ctxptr, c.end.next.idx, oldOffset) - store(ctxptr, c.end.next.elemIdx, uintptr(unsafe.Pointer(code.next))) - code = c - recursiveLevel++ - case opStructFieldRecursiveEnd: - recursiveLevel-- - - // restore ctxptr - offset := load(ctxptr, code.idx) - ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1] - - codePtr := load(ctxptr, code.elemIdx) - code = (*opcode)(ptrToUnsafePtr(codePtr)) - ctxptr = ctx.ptr() + offset - ptrOffset = offset - case opStructFieldPtrHead: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHead: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if !code.anonymousKey && len(code.escapedKey) > 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - } - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmpty: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmpty: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - p += code.offset - if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadStringTag: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTag: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - p += code.offset - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendInt(b, ptrToUint64(p+code.offset), code) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - u64 := ptrToUint64(p + code.offset) - v := u64 & code.mask - if v == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendInt(b, u64, code) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = appendInt(b, ptrToUint64(p+code.offset), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendInt(b, ptrToUint64(p), code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendUint(b, ptrToUint64(p+code.offset), code) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - u64 := ptrToUint64(p + code.offset) - v := u64 & code.mask - if v == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendUint(b, u64, code) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = appendUint(b, ptrToUint64(p+code.offset), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendUint(b, ptrToUint64(p), code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat32(b, ptrToFloat32(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToFloat32(p + code.offset) - if v == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat32(b, v) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = encodeFloat32(b, ptrToFloat32(p+code.offset)) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat32(b, ptrToFloat32(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - if v == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeEscapedString(b, ptrToString(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToString(p + code.offset) - if v == "" { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeEscapedString(b, v) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - v := ptrToString(p + code.offset) - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, v))) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, ptrToString(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeEscapedString(b, ptrToString(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, ptrToString(p)))) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeBool(b, ptrToBool(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToBool(p + code.offset) - if v { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeBool(b, v) - b = encodeIndentComma(b) - code = code.next - } else { - code = code.nextField - } - case opStructFieldPtrHeadStringTagBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = encodeBool(b, ptrToBool(p+code.offset)) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p+code.offset)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeBool(b, ptrToBool(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToBytes(p + code.offset) - if len(v) == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeByteSlice(b, v) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeByteSlice(b, ptrToBytes(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldHeadNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opStructFieldPtrHeadOmitEmptyNumber: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToNumber(p + code.offset) - if v == "" { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - } - case opStructFieldPtrHeadStringTagNumber: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.escapedKey...) - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldPtrHeadStringTagNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadArray, opStructFieldPtrHeadStringTagArray, - opStructFieldPtrHeadSlice, opStructFieldPtrHeadStringTagSlice: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadArray, opStructFieldHeadStringTagArray, - opStructFieldHeadSlice, opStructFieldHeadStringTagSlice: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptyArray: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyArray: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - p += code.offset - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptySlice: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptySlice: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - p += code.offset - slice := ptrToSlice(p) - if slice.data == nil { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadArrayPtr, opStructFieldPtrHeadStringTagArrayPtr, - opStructFieldPtrHeadSlicePtr, opStructFieldPtrHeadStringTagSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadArrayPtr, opStructFieldHeadStringTagArrayPtr, - opStructFieldHeadSlicePtr, opStructFieldHeadStringTagSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.nextField - } else { - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadOmitEmptyArrayPtr, opStructFieldPtrHeadOmitEmptySlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyArrayPtr, opStructFieldHeadOmitEmptySlicePtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMap, opStructFieldPtrHeadStringTagMap: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMap, opStructFieldHeadStringTagMap: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if p != 0 && code.indirect { - p = ptrToPtr(p + code.offset) - } - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptyMap: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMap: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if p != 0 && code.indirect { - p = ptrToPtr(p + code.offset) - } - if maplen(ptrToUnsafePtr(p)) == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMapPtr, opStructFieldPtrHeadStringTagMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMapPtr, opStructFieldHeadStringTagMapPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.nextField - break - } - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.nextField - } else { - if code.indirect { - p = ptrToPtr(p) - } - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadOmitEmptyMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMapPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if p == 0 { - code = code.nextField - break - } - p = ptrToPtr(p + code.offset) - if p == 0 { - code = code.nextField - } else { - if code.indirect { - p = ptrToPtr(p) - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadStringTagMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadStringTagMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadStringTagMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadOmitEmptyMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadOmitEmptyMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if p == 0 && code.nilcheck { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = bb - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalJSONPtr, opStructFieldPtrHeadStringTagMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMarshalJSONPtr, opStructFieldHeadStringTagMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if p == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = bb - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadStringTagMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadStringTagMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadStringTagMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadOmitEmptyMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadOmitEmptyMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if p == 0 && code.nilcheck { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalTextPtr, opStructFieldPtrHeadStringTagMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMarshalTextPtr, opStructFieldHeadStringTagMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if p == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - b = encodeIndentComma(b) - code = code.next - } - case opStructField: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmpty: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldStringTag: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldInt: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyInt: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendInt(b, u64, code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagInt: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldIntPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendInt(b, ptrToUint64(p), code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldUint: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyUint: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendUint(b, u64, code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagUint: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldUintPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendUint(b, ptrToUint64(p), code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldFloat32: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyFloat32: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat32(ptr + code.offset) - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat32(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagFloat32: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldFloat32Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat32(b, ptrToFloat32(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldFloat64: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if v != 0 { - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldFloat64Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldString: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeEscapedString(b, ptrToString(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyString: - ptr := load(ctxptr, code.headIdx) - v := ptrToString(ptr + code.offset) - if v != "" { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeEscapedString(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagString: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - s := ptrToString(ptr + code.offset) - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, s))) - b = encodeIndentComma(b) - code = code.next - case opStructFieldStringPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, ptrToString(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyStringPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeEscapedString(b, ptrToString(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagStringPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, ptrToString(p)))) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldBool: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyBool: - ptr := load(ctxptr, code.headIdx) - v := ptrToBool(ptr + code.offset) - if v { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeBool(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagBool: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldBoolPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyBoolPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeBool(b, ptrToBool(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagBoolPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldBytes: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - if len(v) > 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeByteSlice(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagBytes: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldBytesPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyBytesPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagBytesPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldNumber: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opStructFieldOmitEmptyNumber: - p := load(ctxptr, code.headIdx) - v := ptrToNumber(p + code.offset) - if v != "" { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldStringTagNumber: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = append(b, '"') - p := load(ctxptr, code.headIdx) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldNumberPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyNumberPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldStringTagNumberPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldMarshalJSON, opStructFieldStringTagMarshalJSON: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalJSON: - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - code = code.nextField - break - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opStructFieldMarshalJSONPtr, opStructFieldStringTagMarshalJSONPtr: - p := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, true) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldMarshalText, opStructFieldStringTagMarshalText: - p := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalText: - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - code = code.nextField - break - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opStructFieldMarshalTextPtr, opStructFieldStringTagMarshalTextPtr: - p := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), true) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldArray, opStructFieldStringTagArray: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyArray: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldArrayPtr, opStructFieldStringTagArrayPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyArrayPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldSlice, opStructFieldStringTagSlice: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptySlice: - p := load(ctxptr, code.headIdx) - p += code.offset - slice := ptrToSlice(p) - if slice.data == nil { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldSlicePtr, opStructFieldStringTagSlicePtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptySlicePtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldMap, opStructFieldStringTagMap: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyMap: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldMapPtr, opStructFieldStringTagMapPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - p = ptrToPtr(p) - } - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyMapPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - p = ptrToPtr(p) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldStruct: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if p == 0 { - b = append(b, '{', '}', ',', '\n') - code = code.nextField - } else { - headCode := code.next - if headCode.next == headCode.end { - // not exists fields - b = append(b, '{', '}', ',', '\n') - code = code.nextField - } else { - code = code.next - store(ctxptr, code.idx, p) - } - } - case opStructFieldOmitEmptyStruct: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - if p == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - headCode := code.next - if headCode.next == headCode.end { - // not exists fields - b = append(b, '{', '}', ',', '\n') - code = code.nextField - } else { - code = code.next - store(ctxptr, code.idx, p) - } - } - case opStructAnonymousEnd: - code = code.next - case opStructEnd: - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - b = encodeIndentComma(b) - code = code.next - break - } - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent) - b = append(b, '}') - b = encodeIndentComma(b) - code = code.next - case opStructEndInt: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyInt: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendInt(b, u64, code) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagInt: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndIntPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendInt(b, ptrToUint64(p), code) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagIntPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndUint: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyUint: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendUint(b, u64, code) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagUint: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndUintPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = appendUint(b, ptrToUint64(p), code) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagUintPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndFloat32: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyFloat32: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat32(ptr + code.offset) - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat32(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagFloat32: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndFloat32Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeFloat32(b, ptrToFloat32(p)) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagFloat32Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndFloat64: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndFloat64Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagFloat64Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndString: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeEscapedString(b, ptrToString(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyString: - ptr := load(ctxptr, code.headIdx) - v := ptrToString(ptr + code.offset) - if v != "" { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeEscapedString(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagString: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - s := ptrToString(ptr + code.offset) - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, s))) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndStringPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, ptrToString(p)) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyStringPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeEscapedString(b, ptrToString(p)) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagStringPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeEscapedString(b, string(encodeEscapedString([]byte{}, ptrToString(p)))) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndBool: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyBool: - ptr := load(ctxptr, code.headIdx) - v := ptrToBool(ptr + code.offset) - if v { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeBool(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagBool: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ', '"') - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndBoolPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyBoolPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeBool(b, ptrToBool(p)) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagBoolPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndBytes: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - if len(v) > 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = encodeByteSlice(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagBytes: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndNumber: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = appendStructEndIndent(ctx, bb, code.indent-1) - code = code.next - case opStructEndOmitEmptyNumber: - p := load(ctxptr, code.headIdx) - v := ptrToNumber(p + code.offset) - if v != "" { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = appendStructEndIndent(ctx, bb, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagNumber: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - b = append(b, '"') - p := load(ctxptr, code.headIdx) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndNumberPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyNumberPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = appendStructEndIndent(ctx, bb, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagNumberPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.escapedKey...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opEnd: - goto END - } - } -END: - return b, nil -} diff --git a/encode_vm_indent.go b/encode_vm_indent.go deleted file mode 100644 index 3612dc8..0000000 --- a/encode_vm_indent.go +++ /dev/null @@ -1,4532 +0,0 @@ -package json - -import ( - "bytes" - "fmt" - "math" - "reflect" - "sort" - "strings" - "unsafe" -) - -func encodeRunIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt EncodeOption) ([]byte, error) { - recursiveLevel := 0 - ptrOffset := uintptr(0) - ctxptr := ctx.ptr() - code := codeSet.code - - for { - switch code.op { - default: - return nil, fmt.Errorf("encoder (indent): opcode %s has not been implemented", code.op) - case opPtr: - ptr := load(ctxptr, code.idx) - code = code.next - store(ctxptr, code.idx, ptrToPtr(ptr)) - case opInt: - b = appendInt(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = encodeIndentComma(b) - code = code.next - case opUint: - b = appendUint(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = encodeIndentComma(b) - code = code.next - case opIntString: - b = append(b, '"') - b = appendInt(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opUintString: - b = append(b, '"') - b = appendUint(b, ptrToUint64(load(ctxptr, code.idx)), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opFloat32: - b = encodeFloat32(b, ptrToFloat32(load(ctxptr, code.idx))) - b = encodeIndentComma(b) - code = code.next - case opFloat64: - v := ptrToFloat64(load(ctxptr, code.idx)) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - code = code.next - case opString: - b = encodeNoEscapedString(b, ptrToString(load(ctxptr, code.idx))) - b = encodeIndentComma(b) - code = code.next - case opBool: - b = encodeBool(b, ptrToBool(load(ctxptr, code.idx))) - b = encodeIndentComma(b) - code = code.next - case opBytes: - ptr := load(ctxptr, code.idx) - slice := ptrToSlice(ptr) - if ptr == 0 || uintptr(slice.data) == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(ptr)) - } - b = encodeIndentComma(b) - code = code.next - case opNumber: - bb, err := encodeNumber(b, ptrToNumber(load(ctxptr, code.idx))) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opInterface: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.next - break - } - for _, seen := range ctx.seenPtr { - if ptr == seen { - return nil, errUnsupportedValue(code, ptr) - } - } - ctx.seenPtr = append(ctx.seenPtr, ptr) - iface := (*emptyInterface)(ptrToUnsafePtr(ptr)) - if iface == nil || iface.ptr == nil { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.next - break - } - ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := encodeCompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) - if err != nil { - return nil, err - } - - totalLength := uintptr(codeSet.codeLength) - nextTotalLength := uintptr(ifaceCodeSet.codeLength) - - curlen := uintptr(len(ctx.ptrs)) - offsetNum := ptrOffset / uintptrSize - - newLen := offsetNum + totalLength + nextTotalLength - if curlen < newLen { - ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...) - } - oldPtrs := ctx.ptrs - - newPtrs := ctx.ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] - newPtrs[0] = uintptr(iface.ptr) - - ctx.ptrs = newPtrs - - oldBaseIndent := ctx.baseIndent - ctx.baseIndent = code.indent - bb, err := encodeRunIndent(ctx, b, ifaceCodeSet, opt) - if err != nil { - return nil, err - } - ctx.baseIndent = oldBaseIndent - - ctx.ptrs = oldPtrs - ctxptr = ctx.ptr() - ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1] - - b = bb - code = code.next - case opMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.next - break - } - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opMarshalText: - 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) - slice := ptrToSlice(p) - if p == 0 || slice.data == nil { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.end.next - } else { - store(ctxptr, code.elemIdx, 0) - store(ctxptr, code.length, uintptr(slice.len)) - store(ctxptr, code.idx, uintptr(slice.data)) - if slice.len > 0 { - b = append(b, '[', '\n') - b = appendIndent(ctx, b, code.indent+1) - code = code.next - store(ctxptr, code.idx, uintptr(slice.data)) - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, '[', ']', ',', '\n') - code = code.end.next - } - } - case opSliceElem: - idx := load(ctxptr, code.elemIdx) - length := load(ctxptr, code.length) - idx++ - if idx < length { - b = appendIndent(ctx, b, code.indent+1) - store(ctxptr, code.elemIdx, idx) - data := load(ctxptr, code.headIdx) - size := code.size - code = code.next - store(ctxptr, code.idx, data+idx*size) - } else { - b = b[:len(b)-2] - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent) - b = append(b, ']', ',', '\n') - code = code.end.next - } - case opArray: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.end.next - } else { - if code.length > 0 { - b = append(b, '[', '\n') - b = appendIndent(ctx, b, code.indent+1) - store(ctxptr, code.elemIdx, 0) - code = code.next - store(ctxptr, code.idx, p) - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, '[', ']', ',', '\n') - code = code.end.next - } - } - case opArrayElem: - idx := load(ctxptr, code.elemIdx) - idx++ - if idx < code.length { - b = appendIndent(ctx, b, code.indent+1) - store(ctxptr, code.elemIdx, idx) - p := load(ctxptr, code.headIdx) - size := code.size - code = code.next - store(ctxptr, code.idx, p+idx*size) - } else { - b = b[:len(b)-2] - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent) - b = append(b, ']', ',', '\n') - code = code.end.next - } - case opMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opMap: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.end.next - } else { - uptr := ptrToUnsafePtr(ptr) - mlen := maplen(uptr) - if mlen > 0 { - b = append(b, '{', '\n') - iter := mapiterinit(code.typ, uptr) - ctx.keepRefs = append(ctx.keepRefs, iter) - store(ctxptr, code.elemIdx, 0) - store(ctxptr, code.length, uintptr(mlen)) - store(ctxptr, code.mapIter, uintptr(iter)) - - if (opt & EncodeOptionUnorderedMap) == 0 { - mapCtx := newMapContext(mlen) - mapCtx.pos = append(mapCtx.pos, len(b)) - ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(mapCtx)) - store(ctxptr, code.end.mapPos, uintptr(unsafe.Pointer(mapCtx))) - } else { - b = appendIndent(ctx, b, code.next.indent) - } - - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - b = append(b, '{', '}', ',', '\n') - code = code.end.next - } - } - case opMapKey: - idx := load(ctxptr, code.elemIdx) - length := load(ctxptr, code.length) - idx++ - if (opt & EncodeOptionUnorderedMap) != 0 { - if idx < length { - b = appendIndent(ctx, b, code.indent) - store(ctxptr, code.elemIdx, idx) - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - last := len(b) - 1 - b[last] = '\n' - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}', ',', '\n') - code = code.end.next - } - } else { - ptr := load(ctxptr, code.end.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - mapCtx.pos = append(mapCtx.pos, len(b)) - if idx < length { - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - store(ctxptr, code.elemIdx, idx) - key := mapiterkey(iter) - store(ctxptr, code.next.idx, uintptr(key)) - code = code.next - } else { - code = code.end - } - } - case opMapValue: - if (opt & EncodeOptionUnorderedMap) != 0 { - b = append(b, ':', ' ') - } else { - ptr := load(ctxptr, code.end.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - mapCtx.pos = append(mapCtx.pos, len(b)) - } - ptr := load(ctxptr, code.mapIter) - iter := ptrToUnsafePtr(ptr) - value := mapitervalue(iter) - store(ctxptr, code.next.idx, uintptr(value)) - mapiternext(iter) - code = code.next - case opMapEnd: - // this operation only used by sorted map - length := int(load(ctxptr, code.length)) - ptr := load(ctxptr, code.mapPos) - mapCtx := (*encodeMapContext)(ptrToUnsafePtr(ptr)) - pos := mapCtx.pos - for i := 0; i < length; i++ { - startKey := pos[i*2] - startValue := pos[i*2+1] - var endValue int - if i+1 < length { - endValue = pos[i*2+2] - } else { - endValue = len(b) - } - mapCtx.slice.items = append(mapCtx.slice.items, mapItem{ - key: b[startKey:startValue], - value: b[startValue:endValue], - }) - } - sort.Sort(mapCtx.slice) - buf := mapCtx.buf - for _, item := range mapCtx.slice.items { - buf = append(buf, ctx.prefix...) - buf = append(buf, bytes.Repeat(ctx.indentStr, ctx.baseIndent+code.indent+1)...) - buf = append(buf, item.key...) - buf[len(buf)-2] = ':' - buf[len(buf)-1] = ' ' - buf = append(buf, item.value...) - } - buf = buf[:len(buf)-2] - buf = append(buf, '\n') - buf = append(buf, ctx.prefix...) - buf = append(buf, bytes.Repeat(ctx.indentStr, ctx.baseIndent+code.indent)...) - buf = append(buf, '}', ',', '\n') - - b = b[:pos[0]] - b = append(b, buf...) - mapCtx.buf = buf - releaseMapContext(mapCtx) - code = code.next - case opStructFieldPtrHeadRecursive: - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - case opStructFieldRecursive: - ptr := load(ctxptr, code.idx) - if ptr != 0 { - if recursiveLevel > startDetectingCyclesAfter { - for _, seen := range ctx.seenPtr { - if ptr == seen { - return nil, errUnsupportedValue(code, ptr) - } - } - } - } - ctx.seenPtr = append(ctx.seenPtr, ptr) - c := code.jmp.code - curlen := uintptr(len(ctx.ptrs)) - offsetNum := ptrOffset / uintptrSize - oldOffset := ptrOffset - ptrOffset += code.jmp.curLen * uintptrSize - - newLen := offsetNum + code.jmp.curLen + code.jmp.nextLen - if curlen < newLen { - ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...) - } - ctxptr = ctx.ptr() + ptrOffset // assign new ctxptr - - store(ctxptr, c.idx, ptr) - store(ctxptr, c.end.next.idx, oldOffset) - store(ctxptr, c.end.next.elemIdx, uintptr(unsafe.Pointer(code.next))) - code = c - recursiveLevel++ - case opStructFieldRecursiveEnd: - recursiveLevel-- - - // restore ctxptr - offset := load(ctxptr, code.idx) - ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1] - - codePtr := load(ctxptr, code.elemIdx) - code = (*opcode)(ptrToUnsafePtr(codePtr)) - ctxptr = ctx.ptr() + offset - ptrOffset = offset - case opStructFieldPtrHead: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHead: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if !code.anonymousKey && len(code.key) > 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - } - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmpty: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmpty: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - p += code.offset - if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadStringTag: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTag: - p := load(ctxptr, code.idx) - if p == 0 && (code.indirect || code.next.op == opStructEnd) { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - p += code.offset - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = appendInt(b, ptrToUint64(p+code.offset), code) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - u64 := ptrToUint64(p + code.offset) - v := u64 & code.mask - if v == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = appendInt(b, u64, code) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagInt: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagInt: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = appendInt(b, ptrToUint64(p+code.offset), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = appendInt(b, ptrToUint64(p), code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagIntPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagIntPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - - case opStructFieldPtrHeadUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = appendUint(b, ptrToUint64(p+code.offset), code) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - u64 := ptrToUint64(p + code.offset) - v := u64 & code.mask - if v == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = appendUint(b, u64, code) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagUint: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagUint: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = appendUint(b, ptrToUint64(p+code.offset), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = appendUint(b, ptrToUint64(p), code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagUintPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagUintPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat32(b, ptrToFloat32(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToFloat32(p + code.offset) - if v == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat32(b, v) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagFloat32: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagFloat32: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = encodeFloat32(b, ptrToFloat32(p+code.offset)) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat32(b, ptrToFloat32(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagFloat32Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - if v == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagFloat64: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagFloat64: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ', '"') - v := ptrToFloat64(p + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagFloat64Ptr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeNoEscapedString(b, ptrToString(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToString(p + code.offset) - if v == "" { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeNoEscapedString(b, v) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagString: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagString: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - v := ptrToString(p + code.offset) - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, v))) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, ptrToString(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeNoEscapedString(b, ptrToString(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagStringPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagStringPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, ptrToString(p)))) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeBool(b, ptrToBool(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToBool(p + code.offset) - if v { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeBool(b, v) - b = encodeIndentComma(b) - code = code.next - } else { - code = code.nextField - } - case opStructFieldPtrHeadStringTagBool: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagBool: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = encodeBool(b, ptrToBool(p+code.offset)) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p+code.offset)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeBool(b, ptrToBool(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagBoolPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToBytes(p + code.offset) - if len(v) == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, v) - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadStringTagBytes: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagBytes: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(p+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldPtrHeadStringTagBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagBytesPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeByteSlice(b, ptrToBytes(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldHeadNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opStructFieldPtrHeadOmitEmptyNumber: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - v := ptrToNumber(p + code.offset) - if v == "" { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - } - case opStructFieldPtrHeadStringTagNumber: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadStringTagNumber: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p != 0 { - b = append(b, code.key...) - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldPtrHeadStringTagNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadStringTagNumberPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadArray, opStructFieldPtrHeadStringTagArray, - opStructFieldPtrHeadSlice, opStructFieldPtrHeadStringTagSlice: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadArray, opStructFieldHeadStringTagArray, - opStructFieldHeadSlice, opStructFieldHeadStringTagSlice: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptyArray: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptyArray: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - p += code.offset - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptySlice: - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) - } - fallthrough - case opStructFieldHeadOmitEmptySlice: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - p += code.offset - slice := ptrToSlice(p) - if slice.data == nil { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadArrayPtr, opStructFieldPtrHeadStringTagArrayPtr, - opStructFieldPtrHeadSlicePtr, opStructFieldPtrHeadStringTagSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadArrayPtr, opStructFieldHeadStringTagArrayPtr, - opStructFieldHeadSlicePtr, opStructFieldHeadStringTagSlicePtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.nextField - } else { - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadOmitEmptyArrayPtr, opStructFieldPtrHeadOmitEmptySlicePtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyArrayPtr, opStructFieldHeadOmitEmptySlicePtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMap, opStructFieldPtrHeadStringTagMap: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMap, opStructFieldHeadStringTagMap: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if p != 0 && code.indirect { - p = ptrToPtr(p + code.offset) - } - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldPtrHeadOmitEmptyMap: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMap: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if p != 0 && code.indirect { - p = ptrToPtr(p + code.offset) - } - if maplen(ptrToUnsafePtr(p)) == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMapPtr, opStructFieldPtrHeadStringTagMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMapPtr, opStructFieldHeadStringTagMapPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.nextField - break - } - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - b = encodeIndentComma(b) - code = code.nextField - } else { - if code.indirect { - p = ptrToPtr(p) - } - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadOmitEmptyMapPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMapPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if p == 0 { - code = code.nextField - break - } - p = ptrToPtr(p + code.offset) - if p == 0 { - code = code.nextField - } else { - if code.indirect { - p = ptrToPtr(p) - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldPtrHeadMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadStringTagMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadStringTagMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadStringTagMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadOmitEmptyMarshalJSON: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadOmitEmptyMarshalJSON { - p = ptrToPtr(p + code.offset) - } - } - if p == 0 && code.nilcheck { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = bb - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalJSONPtr, opStructFieldPtrHeadStringTagMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMarshalJSONPtr, opStructFieldHeadStringTagMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if p == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = bb - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadStringTagMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadStringTagMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadStringTagMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if code.nilcheck && p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalText: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - store(ctxptr, code.idx, ptrToPtr(p)) - } - fallthrough - case opStructFieldHeadOmitEmptyMarshalText: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if code.typ.Kind() == reflect.Ptr { - if code.indirect || code.op == opStructFieldPtrHeadOmitEmptyMarshalText { - p = ptrToPtr(p + code.offset) - } - } - if p == 0 && code.nilcheck { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - b = encodeIndentComma(b) - code = code.next - } - case opStructFieldPtrHeadMarshalTextPtr, opStructFieldPtrHeadStringTagMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadMarshalTextPtr, opStructFieldHeadStringTagMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldPtrHeadOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - store(ctxptr, code.idx, ptrToPtr(p)) - fallthrough - case opStructFieldHeadOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.idx) - if p == 0 && code.indirect { - if !code.anonymousHead { - b = encodeNull(b) - b = encodeIndentComma(b) - } - code = code.end.next - break - } - if code.indirect { - p = ptrToPtr(p + code.offset) - } - if !code.anonymousHead { - b = append(b, '{', '\n') - } - if p == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent+1) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - b = encodeIndentComma(b) - code = code.next - } - case opStructField: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmpty: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldStringTag: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldInt: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyInt: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = appendInt(b, u64, code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagInt: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldIntPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = appendInt(b, ptrToUint64(p), code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldUint: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyUint: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = appendUint(b, u64, code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagUint: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldUintPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = appendUint(b, ptrToUint64(p), code) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldFloat32: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyFloat32: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat32(ptr + code.offset) - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat32(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagFloat32: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldFloat32Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat32(b, ptrToFloat32(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldFloat64: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if v != 0 { - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldFloat64Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldString: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeNoEscapedString(b, ptrToString(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyString: - ptr := load(ctxptr, code.headIdx) - v := ptrToString(ptr + code.offset) - if v != "" { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeNoEscapedString(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagString: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - s := ptrToString(ptr + code.offset) - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, s))) - b = encodeIndentComma(b) - code = code.next - case opStructFieldStringPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, ptrToString(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyStringPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeNoEscapedString(b, ptrToString(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagStringPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, ptrToString(p)))) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldBool: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyBool: - ptr := load(ctxptr, code.headIdx) - v := ptrToBool(ptr + code.offset) - if v { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeBool(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagBool: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = append(b, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldBoolPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyBoolPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeBool(b, ptrToBool(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagBoolPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldBytes: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - if len(v) > 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, v) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagBytes: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = encodeIndentComma(b) - code = code.next - case opStructFieldBytesPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyBytesPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(p)) - b = encodeIndentComma(b) - } - code = code.next - case opStructFieldStringTagBytesPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeByteSlice(b, ptrToBytes(p)) - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldNumber: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opStructFieldOmitEmptyNumber: - p := load(ctxptr, code.headIdx) - v := ptrToNumber(p + code.offset) - if v != "" { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldStringTagNumber: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = append(b, '"') - p := load(ctxptr, code.headIdx) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = encodeIndentComma(b) - code = code.next - case opStructFieldNumberPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyNumberPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldStringTagNumberPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldMarshalJSON, opStructFieldStringTagMarshalJSON: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalJSON: - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - code = code.nextField - break - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opStructFieldMarshalJSONPtr, opStructFieldStringTagMarshalJSONPtr: - p := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalJSONPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeMarshalJSONIndent(ctx, code, b, ptrToInterface(code, p), code.indent, false) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldMarshalText, opStructFieldStringTagMarshalText: - p := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalText: - p := load(ctxptr, code.headIdx) - p += code.offset - if code.typ.Kind() == reflect.Ptr { - p = ptrToPtr(p) - } - if p == 0 && code.nilcheck { - code = code.nextField - break - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - code = code.next - case opStructFieldMarshalTextPtr, opStructFieldStringTagMarshalTextPtr: - p := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = bb - } - b = encodeIndentComma(b) - code = code.next - case opStructFieldOmitEmptyMarshalTextPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeMarshalTextIndent(code, b, ptrToInterface(code, p), false) - if err != nil { - return nil, err - } - b = encodeIndentComma(bb) - } - code = code.next - case opStructFieldArray, opStructFieldStringTagArray: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyArray: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldArrayPtr, opStructFieldStringTagArrayPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyArrayPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldSlice, opStructFieldStringTagSlice: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p += code.offset - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptySlice: - p := load(ctxptr, code.headIdx) - p += code.offset - slice := ptrToSlice(p) - if slice.data == nil { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldSlicePtr, opStructFieldStringTagSlicePtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptySlicePtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldMap, opStructFieldStringTagMap: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyMap: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } - case opStructFieldMapPtr, opStructFieldStringTagMapPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - p = ptrToPtr(p) - } - code = code.next - store(ctxptr, code.idx, p) - case opStructFieldOmitEmptyMapPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - p = ptrToPtr(p) - } - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - code = code.next - store(ctxptr, code.idx, p) - } else { - code = code.nextField - } - case opStructFieldStruct: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - if p == 0 { - b = append(b, '{', '}', ',', '\n') - code = code.nextField - } else { - headCode := code.next - if headCode.next == headCode.end { - // not exists fields - b = append(b, '{', '}', ',', '\n') - code = code.nextField - } else { - code = code.next - store(ctxptr, code.idx, p) - } - } - case opStructFieldOmitEmptyStruct: - ptr := load(ctxptr, code.headIdx) - p := ptr + code.offset - if p == 0 { - code = code.nextField - } else { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - headCode := code.next - if headCode.next == headCode.end { - // not exists fields - b = append(b, '{', '}', ',', '\n') - code = code.nextField - } else { - code = code.next - store(ctxptr, code.idx, p) - } - } - case opStructAnonymousEnd: - code = code.next - case opStructEnd: - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - b = encodeIndentComma(b) - code = code.next - break - } - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent) - b = append(b, '}') - b = encodeIndentComma(b) - code = code.next - case opStructEndInt: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyInt: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = appendInt(b, u64, code) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagInt: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = appendInt(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndIntPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendInt(b, ptrToUint64(p), code) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyIntPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = appendInt(b, ptrToUint64(p), code) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagIntPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendInt(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndUint: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyUint: - ptr := load(ctxptr, code.headIdx) - u64 := ptrToUint64(ptr + code.offset) - v := u64 & code.mask - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = appendUint(b, u64, code) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagUint: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = appendUint(b, ptrToUint64(ptr+code.offset), code) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndUintPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = appendUint(b, ptrToUint64(p), code) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyUintPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = appendUint(b, ptrToUint64(p), code) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagUintPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = appendUint(b, ptrToUint64(p), code) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndFloat32: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyFloat32: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat32(ptr + code.offset) - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat32(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagFloat32: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = encodeFloat32(b, ptrToFloat32(ptr+code.offset)) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndFloat32Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeFloat32(b, ptrToFloat32(p)) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyFloat32Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeFloat32(b, ptrToFloat32(p)) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagFloat32Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeFloat32(b, ptrToFloat32(p)) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndFloat64: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if v != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagFloat64: - ptr := load(ctxptr, code.headIdx) - v := ptrToFloat64(ptr + code.offset) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = encodeFloat64(b, v) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndFloat64Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyFloat64Ptr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagFloat64Ptr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - v := ptrToFloat64(p) - if math.IsInf(v, 0) || math.IsNaN(v) { - return nil, errUnsupportedFloat(v) - } - b = encodeFloat64(b, v) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndString: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeNoEscapedString(b, ptrToString(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyString: - ptr := load(ctxptr, code.headIdx) - v := ptrToString(ptr + code.offset) - if v != "" { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeNoEscapedString(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagString: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - s := ptrToString(ptr + code.offset) - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, s))) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndStringPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, ptrToString(p)) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyStringPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeNoEscapedString(b, ptrToString(p)) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagStringPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeNoEscapedString(b, string(encodeNoEscapedString([]byte{}, ptrToString(p)))) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndBool: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyBool: - ptr := load(ctxptr, code.headIdx) - v := ptrToBool(ptr + code.offset) - if v { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeBool(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagBool: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ', '"') - b = encodeBool(b, ptrToBool(ptr+code.offset)) - b = append(b, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndBoolPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = encodeBool(b, ptrToBool(p)) - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyBoolPtr: - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeBool(b, ptrToBool(p)) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagBoolPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - p := ptrToPtr(ptr + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - b = encodeBool(b, ptrToBool(p)) - b = append(b, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndBytes: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - ptr := load(ctxptr, code.headIdx) - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyBytes: - ptr := load(ctxptr, code.headIdx) - v := ptrToBytes(ptr + code.offset) - if len(v) > 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, v) - b = appendStructEndIndent(ctx, b, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagBytes: - ptr := load(ctxptr, code.headIdx) - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = encodeByteSlice(b, ptrToBytes(ptr+code.offset)) - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndNumber: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = appendStructEndIndent(ctx, bb, code.indent-1) - code = code.next - case opStructEndOmitEmptyNumber: - p := load(ctxptr, code.headIdx) - v := ptrToNumber(p + code.offset) - if v != "" { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeNumber(b, v) - if err != nil { - return nil, err - } - b = appendStructEndIndent(ctx, bb, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagNumber: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - b = append(b, '"') - p := load(ctxptr, code.headIdx) - bb, err := encodeNumber(b, ptrToNumber(p+code.offset)) - if err != nil { - return nil, err - } - b = append(bb, '"') - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndNumberPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = bb - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opStructEndOmitEmptyNumberPtr: - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p != 0 { - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = appendStructEndIndent(ctx, bb, code.indent-1) - } else { - last := len(b) - 1 - if b[last-1] == '{' { - b[last] = '}' - } else { - if b[last] == '\n' { - // to remove ',' and '\n' characters - b = b[:len(b)-2] - } - b = append(b, '\n') - b = appendIndent(ctx, b, code.indent-1) - b = append(b, '}') - } - b = encodeIndentComma(b) - } - code = code.next - case opStructEndStringTagNumberPtr: - b = appendIndent(ctx, b, code.indent) - b = append(b, code.key...) - b = append(b, ' ') - p := load(ctxptr, code.headIdx) - p = ptrToPtr(p + code.offset) - if p == 0 { - b = encodeNull(b) - } else { - b = append(b, '"') - bb, err := encodeNumber(b, ptrToNumber(p)) - if err != nil { - return nil, err - } - b = append(bb, '"') - } - b = appendStructEndIndent(ctx, b, code.indent-1) - code = code.next - case opEnd: - goto END - } - } -END: - return b, nil -} diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index 2836ec2..b8baf49 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -9,6 +9,7 @@ import ( "math" "reflect" "strconv" + "strings" "sync" "unsafe" @@ -439,6 +440,42 @@ func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]by return buf.Bytes(), nil } +func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}, indent int, escape bool) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if code.AddrForMarshaler { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + marshaler, ok := v.(json.Marshaler) + if !ok { + return AppendNull(b), nil + } + bb, err := marshaler.MarshalJSON() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + var compactBuf bytes.Buffer + if err := compact(&compactBuf, bb, escape); err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + var indentBuf bytes.Buffer + if err := encodeIndent( + &indentBuf, + compactBuf.Bytes(), + string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+indent+1), + string(ctx.IndentStr), + ); err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + return append(b, indentBuf.Bytes()...), nil +} + func AppendMarshalText(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { rv := reflect.ValueOf(v) // convert by dynamic interface type if code.AddrForMarshaler { @@ -465,6 +502,32 @@ func AppendMarshalText(code *Opcode, b []byte, v interface{}, escape bool) ([]by return AppendString(b, *(*string)(unsafe.Pointer(&bytes))), nil } +func AppendMarshalTextIndent(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if code.AddrForMarshaler { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + marshaler, ok := v.(encoding.TextMarshaler) + if !ok { + return AppendNull(b), nil + } + bytes, err := marshaler.MarshalText() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + if escape { + return AppendEscapedString(b, *(*string)(unsafe.Pointer(&bytes))), nil + } + return AppendString(b, *(*string)(unsafe.Pointer(&bytes))), nil +} + func AppendNull(b []byte) []byte { return append(b, "null"...) } @@ -473,10 +536,26 @@ func AppendComma(b []byte) []byte { return append(b, ',') } +func AppendCommaIndent(b []byte) []byte { + return append(b, ',', '\n') +} + func AppendStructEnd(b []byte) []byte { return append(b, '}', ',') } +func AppendStructEndIndent(ctx *RuntimeContext, b []byte, indent int) []byte { + b = append(b, '\n') + b = append(b, ctx.Prefix...) + b = append(b, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+indent)...) + return append(b, '}', ',', '\n') +} + +func AppendIndent(ctx *RuntimeContext, b []byte, indent int) []byte { + b = append(b, ctx.Prefix...) + return append(b, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+indent)...) +} + func IsNilForMarshaler(v interface{}) bool { rv := reflect.ValueOf(v) switch rv.Kind() { diff --git a/internal/encoder/indent.go b/internal/encoder/indent.go new file mode 100644 index 0000000..ac76159 --- /dev/null +++ b/internal/encoder/indent.go @@ -0,0 +1,112 @@ +package encoder + +import ( + "bytes" + + "github.com/goccy/go-json/internal/errors" +) + +func encodeIndent(dst *bytes.Buffer, src []byte, prefix, indentStr string) error { + length := int64(len(src)) + indentNum := 0 + indentBytes := []byte(indentStr) + for cursor := int64(0); cursor < length; cursor++ { + c := src[cursor] + switch c { + case ' ', '\t', '\n', '\r': + continue + case '"': + if err := dst.WriteByte(c); err != nil { + return err + } + for { + cursor++ + if err := dst.WriteByte(src[cursor]); err != nil { + return err + } + switch src[cursor] { + case '\\': + cursor++ + if err := dst.WriteByte(src[cursor]); err != nil { + return err + } + case '"': + goto LOOP_END + case '\000': + return errors.ErrUnexpectedEndOfJSON("string", length) + } + } + case '{': + if cursor+1 < length && src[cursor+1] == '}' { + if _, err := dst.Write([]byte{'{', '}'}); err != nil { + return err + } + cursor++ + } else { + indentNum++ + b := []byte{c, '\n'} + b = append(b, prefix...) + b = append(b, bytes.Repeat(indentBytes, indentNum)...) + if _, err := dst.Write(b); err != nil { + return err + } + } + case '}': + indentNum-- + if indentNum < 0 { + return errors.ErrInvalidCharacter('}', "}", cursor) + } + b := []byte{'\n'} + b = append(b, prefix...) + b = append(b, bytes.Repeat(indentBytes, indentNum)...) + b = append(b, c) + if _, err := dst.Write(b); err != nil { + return err + } + case '[': + if cursor+1 < length && src[cursor+1] == ']' { + if _, err := dst.Write([]byte{'[', ']'}); err != nil { + return err + } + cursor++ + } else { + indentNum++ + b := []byte{c, '\n'} + b = append(b, prefix...) + b = append(b, bytes.Repeat(indentBytes, indentNum)...) + if _, err := dst.Write(b); err != nil { + return err + } + } + case ']': + indentNum-- + if indentNum < 0 { + return errors.ErrInvalidCharacter(']', "]", cursor) + } + b := []byte{'\n'} + b = append(b, prefix...) + b = append(b, bytes.Repeat(indentBytes, indentNum)...) + b = append(b, c) + if _, err := dst.Write(b); err != nil { + return err + } + case ':': + if _, err := dst.Write([]byte{':', ' '}); err != nil { + return err + } + case ',': + b := []byte{',', '\n'} + b = append(b, prefix...) + b = append(b, bytes.Repeat(indentBytes, indentNum)...) + if _, err := dst.Write(b); err != nil { + return err + } + default: + if err := dst.WriteByte(c); err != nil { + return err + } + } + LOOP_END: + } + return nil +} diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index ad4154f..87651de 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -409,7 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) b = appendComma(b) - code = code.Next + code = code.End.Next break } store(ctxptr, code.Idx, p) @@ -3794,7 +3794,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) p += code.Offset slice := ptrToSlice(p) - if p == 0 || slice.Data == nil { + if slice.Data == nil { code = code.NextField } else { b = append(b, code.Key...) @@ -3820,12 +3820,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldMap, encoder.OpStructFieldStringTagMap: b = append(b, code.Key...) p := load(ctxptr, code.HeadIdx) - p = ptrToNPtr(p+code.Offset, code.PtrNum+1) + p = ptrToPtr(p + code.Offset) code = code.Next store(ctxptr, code.Idx, p) case encoder.OpStructFieldOmitEmptyMap: p := load(ctxptr, code.HeadIdx) - p = ptrToNPtr(p+code.Offset, code.PtrNum+1) + p = ptrToPtr(p + code.Offset) if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { code = code.NextField } else { diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go index 4bee00f..7843e6a 100644 --- a/internal/encoder/vm_escaped/vm.go +++ b/internal/encoder/vm_escaped/vm.go @@ -3794,7 +3794,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) p += code.Offset slice := ptrToSlice(p) - if p == 0 || slice.Data == nil { + if slice.Data == nil { code = code.NextField } else { b = append(b, code.EscapedKey...) @@ -3820,12 +3820,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldMap, encoder.OpStructFieldStringTagMap: b = append(b, code.EscapedKey...) p := load(ctxptr, code.HeadIdx) - p = ptrToNPtr(p+code.Offset, code.PtrNum+1) + p = ptrToPtr(p + code.Offset) code = code.Next store(ctxptr, code.Idx, p) case encoder.OpStructFieldOmitEmptyMap: p := load(ctxptr, code.HeadIdx) - p = ptrToNPtr(p+code.Offset, code.PtrNum+1) + p = ptrToPtr(p + code.Offset) if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { code = code.NextField } else { diff --git a/internal/encoder/vm_escaped_indent/vm.go b/internal/encoder/vm_escaped_indent/vm.go new file mode 100644 index 0000000..e64d975 --- /dev/null +++ b/internal/encoder/vm_escaped_indent/vm.go @@ -0,0 +1,4993 @@ +package vm_escaped_indent + +import ( + "bytes" + "fmt" + "math" + "reflect" + "sort" + "strings" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +var ( + load = encoder.Load + store = encoder.Store + loadNPtr = encoder.LoadNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendEscapedString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSONIndent + appendMarshalText = encoder.AppendMarshalTextIndent + appendNull = encoder.AppendNull + appendComma = encoder.AppendCommaIndent + appendIndent = encoder.AppendIndent + appendStructEnd = encoder.AppendStructEndIndent + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + errMarshalerWithCode = encoder.ErrMarshalerWithCode + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + code := codeSet.Code + + for { + switch code.Op { + default: + return nil, fmt.Errorf("encoder (indent): opcode %s has not been implemented", code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpUintPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpFloat32Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpFloat64Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStringPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpString: + b = appendString(b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBoolPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBool: + b = appendBool(b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBytesPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpNumberPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpInterfacePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(codeSet.CodeLength) + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + oldPtrs := ctx.Ptrs + + newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] + newPtrs[0] = uintptr(iface.ptr) + + ctx.Ptrs = newPtrs + + oldBaseIndent := ctx.BaseIndent + ctx.BaseIndent = code.Indent + bb, err := Run(ctx, b, ifaceCodeSet, opt) + if err != nil { + return nil, err + } + ctx.BaseIndent = oldBaseIndent + + ctx.Ptrs = oldPtrs + ctxptr = ctx.Ptr() + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + b = bb + code = code.Next + case encoder.OpMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpSlicePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + store(ctxptr, code.Idx, uintptr(slice.Data)) + if slice.Len > 0 { + b = append(b, '[', '\n') + b = appendIndent(ctx, b, code.Indent+1) + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, '[', ']', ',', '\n') + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + b = appendIndent(ctx, b, code.Indent+1) + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + b = b[:len(b)-2] + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + b = append(b, ']', ',', '\n') + code = code.End.Next + } + case encoder.OpArrayPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + if code.Length > 0 { + b = append(b, '[', '\n') + b = appendIndent(ctx, b, code.Indent+1) + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, '[', ']', ',', '\n') + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < code.Length { + b = appendIndent(ctx, b, code.Indent+1) + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + b = b[:len(b)-2] + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + b = append(b, ']', ',', '\n') + code = code.End.Next + } + case encoder.OpMapPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = append(b, '{', '}', ',', '\n') + code = code.End.Next + break + } + b = append(b, '{', '\n') + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (opt & encoder.UnorderedMapOption) == 0 { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } else { + b = appendIndent(ctx, b, code.Next.Indent) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (opt & encoder.UnorderedMapOption) != 0 { + if idx < length { + b = appendIndent(ctx, b, code.Indent) + store(ctxptr, code.ElemIdx, idx) + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + last := len(b) - 1 + b[last] = '\n' + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}', ',', '\n') + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (opt & encoder.UnorderedMapOption) != 0 { + b = append(b, ':', ' ') + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = append(buf, ctx.Prefix...) + buf = append(buf, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+code.Indent+1)...) + buf = append(buf, item.Key...) + buf[len(buf)-2] = ':' + buf[len(buf)-1] = ' ' + buf = append(buf, item.Value...) + } + buf = buf[:len(buf)-2] + buf = append(buf, '\n') + buf = append(buf, ctx.Prefix...) + buf = append(buf, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+code.Indent)...) + buf = append(buf, '}', ',', '\n') + + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpStructFieldRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructFieldRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + code = c + recursiveLevel++ + case encoder.OpStructFieldRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if !code.AnonymousKey && len(code.Key) > 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + } + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + p += code.Offset + if p == 0 || (ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr")) { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadStringTag: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTag: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + p += code.Offset + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendInt(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendUint(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToFloat32(p + code.Offset) + if v == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat32(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if v == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToString(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendString(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + v := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, v))) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToBool(p + code.Offset) + if v { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendBool(b, v) + b = appendComma(b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadStringTagBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p+code.Offset)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToBytes(p + code.Offset) + if len(v) == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToPtr(p + code.Offset) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToNumber(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.EscapedKey...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadStringTagArray, + encoder.OpStructPtrHeadSlice, encoder.OpStructPtrHeadStringTagSlice: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadStringTagArray, + encoder.OpStructHeadSlice, encoder.OpStructHeadStringTagSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + p += code.Offset + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + p += code.Offset + slice := ptrToSlice(p) + if slice.Data == nil { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadStringTagArrayPtr, + encoder.OpStructPtrHeadSlicePtr, encoder.OpStructPtrHeadStringTagSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadStringTagArrayPtr, + encoder.OpStructHeadSlicePtr, encoder.OpStructHeadStringTagSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap, encoder.OpStructPtrHeadStringTagMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMap, encoder.OpStructHeadStringTagMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr, encoder.OpStructPtrHeadStringTagMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMapPtr, encoder.OpStructHeadStringTagMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + iface := ptrToInterface(code, p) + if code.Nilcheck && encoder.IsNilForMarshaler(iface) { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendMarshalJSON(ctx, code, b, iface, code.Indent, true) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr, encoder.OpStructPtrHeadStringTagMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr, encoder.OpStructHeadStringTagMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if p == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr, encoder.OpStructPtrHeadStringTagMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalTextPtr, encoder.OpStructHeadStringTagMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if p == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructField: + if !code.AnonymousKey { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + } + p := load(ctxptr, code.HeadIdx) + code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr") { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldStringTag: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldInt: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendInt(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldIntPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUint: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendUint(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUintPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat32(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldString: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendString(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagString: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldStringPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagStringPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBool: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendBool(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBoolPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBoolPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytes: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytes: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytesPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytesPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumber: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumber: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = append(b, '"') + p := load(ctxptr, code.HeadIdx) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumberPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumberPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldMarshalJSON, encoder.OpStructFieldStringTagMarshalJSON: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr, encoder.OpStructFieldStringTagMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText, encoder.OpStructFieldStringTagMarshalText: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr, encoder.OpStructFieldStringTagMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldArray, encoder.OpStructFieldStringTagArray: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr, encoder.OpStructFieldStringTagArrayPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice, encoder.OpStructFieldStringTagSlice: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + slice := ptrToSlice(p) + if slice.Data == nil { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr, encoder.OpStructFieldStringTagSlicePtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap, encoder.OpStructFieldStringTagMap: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr, encoder.OpStructFieldStringTagMapPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct, encoder.OpStructFieldStringTagStruct: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyStruct: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr") { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEnd: + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + b = appendComma(b) + code = code.Next + break + } + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + b = append(b, '}') + b = appendComma(b) + code = code.Next + case encoder.OpStructEndInt: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendInt(b, u64, code) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndIntPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendInt(b, ptrToUint64(p), code) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagIntPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndUint: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendUint(b, u64, code) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndUintPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendUint(b, ptrToUint64(p), code) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagUintPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndFloat32: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat32(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendFloat32(b, ptrToFloat32(p)) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagFloat32Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndFloat64: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagFloat64Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndString: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendString(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagString: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndStringPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendString(b, ptrToString(p)) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagStringPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndBool: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendBool(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ', '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndBoolPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendBool(b, ptrToBool(p)) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagBoolPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndBytes: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagBytes: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndBytesPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p)) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagBytesPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndNumber: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, bb, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, bb, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagNumber: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + b = append(b, '"') + p := load(ctxptr, code.HeadIdx) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndNumberPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, bb, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagNumberPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.EscapedKey...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go new file mode 100644 index 0000000..fcae72c --- /dev/null +++ b/internal/encoder/vm_indent/vm.go @@ -0,0 +1,4993 @@ +package vm_indent + +import ( + "bytes" + "fmt" + "math" + "reflect" + "sort" + "strings" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +var ( + load = encoder.Load + store = encoder.Store + loadNPtr = encoder.LoadNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSONIndent + appendMarshalText = encoder.AppendMarshalTextIndent + appendNull = encoder.AppendNull + appendComma = encoder.AppendCommaIndent + appendIndent = encoder.AppendIndent + appendStructEnd = encoder.AppendStructEndIndent + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + errMarshalerWithCode = encoder.ErrMarshalerWithCode + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + code := codeSet.Code + + for { + switch code.Op { + default: + return nil, fmt.Errorf("encoder (indent): opcode %s has not been implemented", code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpUintPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpFloat32Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpFloat64Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStringPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpString: + b = appendString(b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBoolPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBool: + b = appendBool(b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBytesPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpNumberPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpInterfacePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(codeSet.CodeLength) + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + oldPtrs := ctx.Ptrs + + newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] + newPtrs[0] = uintptr(iface.ptr) + + ctx.Ptrs = newPtrs + + oldBaseIndent := ctx.BaseIndent + ctx.BaseIndent = code.Indent + bb, err := Run(ctx, b, ifaceCodeSet, opt) + if err != nil { + return nil, err + } + ctx.BaseIndent = oldBaseIndent + + ctx.Ptrs = oldPtrs + ctxptr = ctx.Ptr() + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + b = bb + code = code.Next + case encoder.OpMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpSlicePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + store(ctxptr, code.Idx, uintptr(slice.Data)) + if slice.Len > 0 { + b = append(b, '[', '\n') + b = appendIndent(ctx, b, code.Indent+1) + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, '[', ']', ',', '\n') + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + b = appendIndent(ctx, b, code.Indent+1) + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + b = b[:len(b)-2] + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + b = append(b, ']', ',', '\n') + code = code.End.Next + } + case encoder.OpArrayPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + if code.Length > 0 { + b = append(b, '[', '\n') + b = appendIndent(ctx, b, code.Indent+1) + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, '[', ']', ',', '\n') + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < code.Length { + b = appendIndent(ctx, b, code.Indent+1) + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + b = b[:len(b)-2] + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + b = append(b, ']', ',', '\n') + code = code.End.Next + } + case encoder.OpMapPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = append(b, '{', '}', ',', '\n') + code = code.End.Next + break + } + b = append(b, '{', '\n') + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (opt & encoder.UnorderedMapOption) == 0 { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } else { + b = appendIndent(ctx, b, code.Next.Indent) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (opt & encoder.UnorderedMapOption) != 0 { + if idx < length { + b = appendIndent(ctx, b, code.Indent) + store(ctxptr, code.ElemIdx, idx) + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + last := len(b) - 1 + b[last] = '\n' + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}', ',', '\n') + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (opt & encoder.UnorderedMapOption) != 0 { + b = append(b, ':', ' ') + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = append(buf, ctx.Prefix...) + buf = append(buf, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+code.Indent+1)...) + buf = append(buf, item.Key...) + buf[len(buf)-2] = ':' + buf[len(buf)-1] = ' ' + buf = append(buf, item.Value...) + } + buf = buf[:len(buf)-2] + buf = append(buf, '\n') + buf = append(buf, ctx.Prefix...) + buf = append(buf, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+code.Indent)...) + buf = append(buf, '}', ',', '\n') + + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpStructFieldRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructFieldRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + code = c + recursiveLevel++ + case encoder.OpStructFieldRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if !code.AnonymousKey && len(code.Key) > 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + } + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + p += code.Offset + if p == 0 || (ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr")) { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadStringTag: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTag: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + p += code.Offset + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendInt(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagInt: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendUint(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagUint: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToFloat32(p + code.Offset) + if v == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat32(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat32: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if v == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat64: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ', '"') + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToString(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendString(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagString: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + v := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, v))) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToBool(p + code.Offset) + if v { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendBool(b, v) + b = appendComma(b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadStringTagBool: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p+code.Offset)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToBytes(p + code.Offset) + if len(v) == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagBytes: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToPtr(p + code.Offset) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + v := ptrToNumber(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagNumber: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringTagNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadStringTagArray, + encoder.OpStructPtrHeadSlice, encoder.OpStructPtrHeadStringTagSlice: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadStringTagArray, + encoder.OpStructHeadSlice, encoder.OpStructHeadStringTagSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + p += code.Offset + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if code.Indirect { + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + p += code.Offset + slice := ptrToSlice(p) + if slice.Data == nil { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadStringTagArrayPtr, + encoder.OpStructPtrHeadSlicePtr, encoder.OpStructPtrHeadStringTagSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadStringTagArrayPtr, + encoder.OpStructHeadSlicePtr, encoder.OpStructHeadStringTagSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap, encoder.OpStructPtrHeadStringTagMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMap, encoder.OpStructHeadStringTagMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr, encoder.OpStructPtrHeadStringTagMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMapPtr, encoder.OpStructHeadStringTagMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + iface := ptrToInterface(code, p) + if code.Nilcheck && encoder.IsNilForMarshaler(iface) { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendMarshalJSON(ctx, code, b, iface, code.Indent, false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr, encoder.OpStructPtrHeadStringTagMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr, encoder.OpStructHeadStringTagMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if p == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringTagMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr, encoder.OpStructPtrHeadStringTagMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalTextPtr, encoder.OpStructHeadStringTagMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{', '\n') + } + if p == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructField: + if !code.AnonymousKey { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + } + p := load(ctxptr, code.HeadIdx) + code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr") { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldStringTag: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldInt: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendInt(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldIntPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUint: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendUint(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUintPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat32(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldString: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendString(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagString: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldStringPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagStringPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBool: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendBool(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBoolPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBoolPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytes: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytes: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytesPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytesPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumber: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumber: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = append(b, '"') + p := load(ctxptr, code.HeadIdx) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumberPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumberPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldMarshalJSON, encoder.OpStructFieldStringTagMarshalJSON: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr, encoder.OpStructFieldStringTagMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText, encoder.OpStructFieldStringTagMarshalText: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr, encoder.OpStructFieldStringTagMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldArray, encoder.OpStructFieldStringTagArray: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr, encoder.OpStructFieldStringTagArrayPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice, encoder.OpStructFieldStringTagSlice: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + slice := ptrToSlice(p) + if slice.Data == nil { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr, encoder.OpStructFieldStringTagSlicePtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap, encoder.OpStructFieldStringTagMap: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr, encoder.OpStructFieldStringTagMapPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct, encoder.OpStructFieldStringTagStruct: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyStruct: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr") { + code = code.NextField + } else { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEnd: + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + b = appendComma(b) + code = code.Next + break + } + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + b = append(b, '}') + b = appendComma(b) + code = code.Next + case encoder.OpStructEndInt: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendInt(b, u64, code) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndIntPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendInt(b, ptrToUint64(p), code) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagIntPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndUint: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendUint(b, u64, code) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndUintPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendUint(b, ptrToUint64(p), code) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagUintPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndFloat32: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat32(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendFloat32(b, ptrToFloat32(p)) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagFloat32Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndFloat64: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagFloat64Ptr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndString: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendString(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagString: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndStringPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendString(b, ptrToString(p)) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagStringPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndBool: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendBool(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ', '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndBoolPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendBool(b, ptrToBool(p)) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagBoolPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndBytes: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, v) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagBytes: + p := load(ctxptr, code.HeadIdx) + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndBytesPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = appendByteSlice(b, ptrToBytes(p)) + b = appendStructEnd(ctx, b, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagBytesPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndNumber: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, bb, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, bb, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagNumber: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + b = append(b, '"') + p := load(ctxptr, code.HeadIdx) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndNumberPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, bb, code.Indent-1) + } else { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + b = appendComma(b) + } + code = code.Next + case encoder.OpStructEndStringTagNumberPtr: + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + b = append(b, ' ') + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(ctx, b, code.Indent-1) + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} From 4db967f28d6913049a78a689be91bff5c7c4b4d3 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 15:53:22 +0900 Subject: [PATCH 08/15] Remove unnecessary files --- codec.go | 19 - compact.go | 54 - decode_compile.go | 5 + encode_compile.go | 1424 ----------------- encode_compile_norace.go | 34 - encode_compile_race.go | 44 - encode_context.go | 164 -- encode_int.go | 124 -- encode_map112.go | 8 - encode_map113.go | 8 - encode_opcode.go | 512 ------ encode_optype.go | 1186 -------------- encode_string.go | 637 -------- encode_vm.go | 66 - internal/encoder/compact.go | 2 +- .../encoder/encode_opcode_test.go | 6 +- internal/encoder/encoder.go | 6 +- internal/encoder/indent.go | 2 +- json.go | 6 +- 19 files changed, 17 insertions(+), 4290 deletions(-) delete mode 100644 compact.go delete mode 100644 encode_compile.go delete mode 100644 encode_compile_norace.go delete mode 100644 encode_compile_race.go delete mode 100644 encode_context.go delete mode 100644 encode_int.go delete mode 100644 encode_map112.go delete mode 100644 encode_map113.go delete mode 100644 encode_opcode.go delete mode 100644 encode_optype.go delete mode 100644 encode_string.go delete mode 100644 encode_vm.go rename encode_opcode_test.go => internal/encoder/encode_opcode_test.go (73%) diff --git a/codec.go b/codec.go index 96b917a..8818bb5 100644 --- a/codec.go +++ b/codec.go @@ -12,8 +12,6 @@ const ( ) var ( - cachedOpcodeSets []*opcodeSet - cachedOpcodeMap unsafe.Pointer // map[uintptr]*opcodeSet cachedDecoder []decoder cachedDecoderMap unsafe.Pointer // map[uintptr]decoder baseTypeAddr uintptr @@ -66,7 +64,6 @@ func setupCodec() error { if addrRange > maxAcceptableTypeAddrRange { return fmt.Errorf("too big address range %d", addrRange) } - cachedOpcodeSets = make([]*opcodeSet, addrRange) cachedDecoder = make([]decoder, addrRange) baseTypeAddr = min maxTypeAddr = max @@ -77,22 +74,6 @@ func init() { _ = setupCodec() } -func loadOpcodeMap() map[uintptr]*opcodeSet { - p := atomic.LoadPointer(&cachedOpcodeMap) - return *(*map[uintptr]*opcodeSet)(unsafe.Pointer(&p)) -} - -func storeOpcodeSet(typ uintptr, set *opcodeSet, m map[uintptr]*opcodeSet) { - newOpcodeMap := make(map[uintptr]*opcodeSet, len(m)+1) - newOpcodeMap[typ] = set - - for k, v := range m { - newOpcodeMap[k] = v - } - - atomic.StorePointer(&cachedOpcodeMap, *(*unsafe.Pointer)(unsafe.Pointer(&newOpcodeMap))) -} - func loadDecoderMap() map[uintptr]decoder { p := atomic.LoadPointer(&cachedDecoderMap) return *(*map[uintptr]decoder)(unsafe.Pointer(&p)) diff --git a/compact.go b/compact.go deleted file mode 100644 index 2e568eb..0000000 --- a/compact.go +++ /dev/null @@ -1,54 +0,0 @@ -package json - -import ( - "bytes" -) - -func compact(dst *bytes.Buffer, src []byte, escape bool) error { - if len(src) == 0 { - return errUnexpectedEndOfJSON("", 0) - } - length := len(src) - for cursor := 0; cursor < length; cursor++ { - c := src[cursor] - switch c { - case ' ', '\t', '\n', '\r': - continue - case '"': - if err := dst.WriteByte(c); err != nil { - return err - } - for { - cursor++ - c := src[cursor] - if escape && (c == '<' || c == '>' || c == '&') { - if _, err := dst.WriteString(`\u00`); err != nil { - return err - } - if _, err := dst.Write([]byte{hex[c>>4], hex[c&0xF]}); err != nil { - return err - } - } else if err := dst.WriteByte(c); err != nil { - return err - } - switch c { - case '\\': - cursor++ - if err := dst.WriteByte(src[cursor]); err != nil { - return err - } - case '"': - goto LOOP_END - case nul: - return errUnexpectedEndOfJSON("string", int64(length)) - } - } - default: - if err := dst.WriteByte(c); err != nil { - return err - } - } - LOOP_END: - } - return nil -} diff --git a/decode_compile.go b/decode_compile.go index e6ed018..8ec2fd0 100644 --- a/decode_compile.go +++ b/decode_compile.go @@ -1,6 +1,7 @@ package json import ( + "encoding/json" "fmt" "reflect" "strings" @@ -8,6 +9,10 @@ import ( "unsafe" ) +var ( + jsonNumberType = reflect.TypeOf(json.Number("")) +) + func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *rtype) (decoder, error) { decoderMap := loadDecoderMap() if dec, exists := decoderMap[typeptr]; exists { diff --git a/encode_compile.go b/encode_compile.go deleted file mode 100644 index fcb89cb..0000000 --- a/encode_compile.go +++ /dev/null @@ -1,1424 +0,0 @@ -package json - -import ( - "encoding" - "fmt" - "math" - "reflect" - "strings" - "unsafe" -) - -type compiledCode struct { - code *opcode - linked bool // whether recursive code already have linked - curLen uintptr - nextLen uintptr -} - -type opcodeSet struct { - code *opcode - codeLength int -} - -var ( - marshalJSONType = reflect.TypeOf((*Marshaler)(nil)).Elem() - marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() - jsonNumberType = reflect.TypeOf(Number("")) -) - -func encodeCompileToGetCodeSetSlowPath(typeptr uintptr) (*opcodeSet, error) { - opcodeMap := loadOpcodeMap() - if codeSet, exists := opcodeMap[typeptr]; exists { - return codeSet, nil - } - - // noescape trick for header.typ ( reflect.*rtype ) - copiedType := *(**rtype)(unsafe.Pointer(&typeptr)) - - code, err := encodeCompileHead(&encodeCompileContext{ - typ: copiedType, - structTypeToCompiledCode: map[uintptr]*compiledCode{}, - }) - if err != nil { - return nil, err - } - code = copyOpcode(code) - codeLength := code.totalLength() - codeSet := &opcodeSet{ - code: code, - codeLength: codeLength, - } - storeOpcodeSet(typeptr, codeSet, opcodeMap) - return codeSet, nil -} - -func encodeCompileHead(ctx *encodeCompileContext) (*opcode, error) { - typ := ctx.typ - switch { - case encodeImplementsMarshalJSON(typ): - return encodeCompileMarshalJSON(ctx) - case encodeImplementsMarshalText(typ): - return encodeCompileMarshalText(ctx) - } - - isPtr := false - orgType := typ - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - isPtr = true - } - switch { - case encodeImplementsMarshalJSON(typ): - return encodeCompileMarshalJSON(ctx) - case encodeImplementsMarshalText(typ): - return encodeCompileMarshalText(ctx) - } - if typ.Kind() == reflect.Map { - if isPtr { - return encodeCompilePtr(ctx.withType(rtype_ptrTo(typ))) - } - return encodeCompileMap(ctx.withType(typ)) - } else if typ.Kind() == reflect.Struct { - code, err := encodeCompileStruct(ctx.withType(typ), isPtr) - if err != nil { - return nil, err - } - encodeOptimizeStructEnd(code) - encodeLinkRecursiveCode(code) - return code, nil - } else if isPtr && typ.Implements(marshalTextType) { - typ = orgType - } - code, err := encodeCompile(ctx.withType(typ), isPtr) - if err != nil { - return nil, err - } - encodeOptimizeStructEnd(code) - encodeLinkRecursiveCode(code) - return code, nil -} - -func encodeLinkRecursiveCode(c *opcode) { - for code := c; code.op != opEnd && code.op != opStructFieldRecursiveEnd; { - switch code.op { - case opStructFieldRecursive, opStructFieldRecursivePtr: - if code.jmp.linked { - code = code.next - continue - } - code.jmp.code = copyOpcode(code.jmp.code) - c := code.jmp.code - c.end.next = newEndOp(&encodeCompileContext{}) - c.op = c.op.ptrHeadToHead() - - beforeLastCode := c.end - lastCode := beforeLastCode.next - - lastCode.idx = beforeLastCode.idx + uintptrSize - lastCode.elemIdx = lastCode.idx + uintptrSize - - // extend length to alloc slot for elemIdx - totalLength := uintptr(code.totalLength() + 1) - nextTotalLength := uintptr(c.totalLength() + 1) - - c.end.next.op = opStructFieldRecursiveEnd - - code.jmp.curLen = totalLength - code.jmp.nextLen = nextTotalLength - code.jmp.linked = true - - encodeLinkRecursiveCode(code.jmp.code) - code = code.next - continue - } - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - default: - code = code.next - } - } -} - -func encodeOptimizeStructEnd(c *opcode) { - for code := c; code.op != opEnd; { - if code.op == opStructFieldRecursive || code.op == opStructFieldRecursivePtr { - // ignore if exists recursive operation - return - } - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - default: - code = code.next - } - } - - for code := c; code.op != opEnd; { - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - case codeStructEnd: - switch code.op { - case opStructEnd: - prev := code.prevField - prevOp := prev.op.String() - if strings.Contains(prevOp, "Head") || - strings.Contains(prevOp, "Slice") || - strings.Contains(prevOp, "Array") || - strings.Contains(prevOp, "Map") || - strings.Contains(prevOp, "MarshalJSON") || - strings.Contains(prevOp, "MarshalText") { - // not exists field - code = code.next - break - } - if prev.op != prev.op.fieldToEnd() { - prev.op = prev.op.fieldToEnd() - prev.next = code.next - } - code = code.next - default: - code = code.next - } - default: - code = code.next - } - } -} - -func encodeImplementsMarshalJSON(typ *rtype) bool { - if !typ.Implements(marshalJSONType) { - return false - } - if typ.Kind() != reflect.Ptr { - return true - } - // type kind is reflect.Ptr - if !typ.Elem().Implements(marshalJSONType) { - return true - } - // needs to dereference - return false -} - -func encodeImplementsMarshalText(typ *rtype) bool { - if !typ.Implements(marshalTextType) { - return false - } - if typ.Kind() != reflect.Ptr { - return true - } - // type kind is reflect.Ptr - if !typ.Elem().Implements(marshalTextType) { - return true - } - // needs to dereference - return false -} - -func encodeCompile(ctx *encodeCompileContext, isPtr bool) (*opcode, error) { - typ := ctx.typ - switch { - case encodeImplementsMarshalJSON(typ): - return encodeCompileMarshalJSON(ctx) - case encodeImplementsMarshalText(typ): - return encodeCompileMarshalText(ctx) - } - switch typ.Kind() { - case reflect.Ptr: - return encodeCompilePtr(ctx) - case reflect.Slice: - elem := typ.Elem() - if elem.Kind() == reflect.Uint8 { - p := rtype_ptrTo(elem) - if !p.Implements(marshalJSONType) && !p.Implements(marshalTextType) { - return encodeCompileBytes(ctx) - } - } - return encodeCompileSlice(ctx) - case reflect.Array: - return encodeCompileArray(ctx) - case reflect.Map: - return encodeCompileMap(ctx) - case reflect.Struct: - return encodeCompileStruct(ctx, isPtr) - case reflect.Interface: - return encodeCompileInterface(ctx) - case reflect.Int: - return encodeCompileInt(ctx) - case reflect.Int8: - return encodeCompileInt8(ctx) - case reflect.Int16: - return encodeCompileInt16(ctx) - case reflect.Int32: - return encodeCompileInt32(ctx) - case reflect.Int64: - return encodeCompileInt64(ctx) - case reflect.Uint: - return encodeCompileUint(ctx) - case reflect.Uint8: - return encodeCompileUint8(ctx) - case reflect.Uint16: - return encodeCompileUint16(ctx) - case reflect.Uint32: - return encodeCompileUint32(ctx) - case reflect.Uint64: - return encodeCompileUint64(ctx) - case reflect.Uintptr: - return encodeCompileUint(ctx) - case reflect.Float32: - return encodeCompileFloat32(ctx) - case reflect.Float64: - return encodeCompileFloat64(ctx) - case reflect.String: - return encodeCompileString(ctx) - case reflect.Bool: - return encodeCompileBool(ctx) - } - return nil, &UnsupportedTypeError{Type: rtype2type(typ)} -} - -func encodeConvertPtrOp(code *opcode) opType { - ptrHeadOp := code.op.headToPtrHead() - if code.op != ptrHeadOp { - return ptrHeadOp - } - switch code.op { - case opInt: - return opIntPtr - case opUint: - return opUintPtr - case opFloat32: - return opFloat32Ptr - case opFloat64: - return opFloat64Ptr - case opString: - return opStringPtr - case opBool: - return opBoolPtr - case opBytes: - return opBytesPtr - case opArray: - return opArrayPtr - case opSlice: - return opSlicePtr - case opMap: - return opMapPtr - case opMarshalJSON: - return opMarshalJSONPtr - case opMarshalText: - return opMarshalTextPtr - case opInterface: - return opInterfacePtr - case opStructFieldRecursive: - return opStructFieldRecursivePtr - } - return code.op -} - -func encodeCompileKey(ctx *encodeCompileContext) (*opcode, error) { - typ := ctx.typ - switch { - case encodeImplementsMarshalJSON(typ): - return encodeCompileMarshalJSON(ctx) - case encodeImplementsMarshalText(typ): - return encodeCompileMarshalText(ctx) - } - switch typ.Kind() { - case reflect.Ptr: - return encodeCompilePtr(ctx) - case reflect.Interface: - return encodeCompileInterface(ctx) - case reflect.String: - return encodeCompileString(ctx) - case reflect.Int: - return encodeCompileIntString(ctx) - case reflect.Int8: - return encodeCompileInt8String(ctx) - case reflect.Int16: - return encodeCompileInt16String(ctx) - case reflect.Int32: - return encodeCompileInt32String(ctx) - case reflect.Int64: - return encodeCompileInt64String(ctx) - case reflect.Uint: - return encodeCompileUintString(ctx) - case reflect.Uint8: - return encodeCompileUint8String(ctx) - case reflect.Uint16: - return encodeCompileUint16String(ctx) - case reflect.Uint32: - return encodeCompileUint32String(ctx) - case reflect.Uint64: - return encodeCompileUint64String(ctx) - case reflect.Uintptr: - return encodeCompileUintString(ctx) - } - return nil, &UnsupportedTypeError{Type: rtype2type(typ)} -} - -func encodeCompilePtr(ctx *encodeCompileContext) (*opcode, error) { - code, err := encodeCompile(ctx.withType(ctx.typ.Elem()), true) - if err != nil { - return nil, err - } - code.op = encodeConvertPtrOp(code) - code.ptrNum++ - return code, nil -} - -func encodeCompileMarshalJSON(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opMarshalJSON) - typ := ctx.typ - if !typ.Implements(marshalJSONType) && rtype_ptrTo(typ).Implements(marshalJSONType) { - code.addrForMarshaler = true - } - ctx.incIndex() - return code, nil -} - -func encodeCompileMarshalText(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opMarshalText) - typ := ctx.typ - if !typ.Implements(marshalTextType) && rtype_ptrTo(typ).Implements(marshalTextType) { - code.addrForMarshaler = true - } - ctx.incIndex() - return code, nil -} - -const intSize = 32 << (^uint(0) >> 63) - -func encodeCompileInt(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - switch intSize { - case 32: - code.mask = math.MaxUint32 - code.rshiftNum = 31 - default: - code.mask = math.MaxUint64 - code.rshiftNum = 63 - } - ctx.incIndex() - return code, nil -} - -func encodeCompileInt8(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - code.mask = math.MaxUint8 - code.rshiftNum = 7 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt16(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - code.mask = math.MaxUint16 - code.rshiftNum = 15 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt32(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - code.mask = math.MaxUint32 - code.rshiftNum = 31 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt64(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opInt) - code.mask = math.MaxUint64 - code.rshiftNum = 63 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - switch intSize { - case 32: - code.mask = math.MaxUint32 - code.rshiftNum = 31 - default: - code.mask = math.MaxUint64 - code.rshiftNum = 63 - } - ctx.incIndex() - return code, nil -} - -func encodeCompileUint8(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - code.mask = math.MaxUint8 - code.rshiftNum = 7 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint16(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - code.mask = math.MaxUint16 - code.rshiftNum = 15 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint32(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - code.mask = math.MaxUint32 - code.rshiftNum = 31 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint64(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUint) - code.mask = math.MaxUint64 - code.rshiftNum = 63 - ctx.incIndex() - return code, nil -} - -func encodeCompileIntString(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - switch intSize { - case 32: - code.mask = math.MaxUint32 - code.rshiftNum = 31 - default: - code.mask = math.MaxUint64 - code.rshiftNum = 63 - } - ctx.incIndex() - return code, nil -} - -func encodeCompileInt8String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - code.mask = math.MaxUint8 - code.rshiftNum = 7 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt16String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - code.mask = math.MaxUint16 - code.rshiftNum = 15 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt32String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - code.mask = math.MaxUint32 - code.rshiftNum = 31 - ctx.incIndex() - return code, nil -} - -func encodeCompileInt64String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opIntString) - code.mask = math.MaxUint64 - code.rshiftNum = 63 - ctx.incIndex() - return code, nil -} - -func encodeCompileUintString(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - switch intSize { - case 32: - code.mask = math.MaxUint32 - code.rshiftNum = 31 - default: - code.mask = math.MaxUint64 - code.rshiftNum = 63 - } - ctx.incIndex() - return code, nil -} - -func encodeCompileUint8String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - code.mask = math.MaxUint8 - code.rshiftNum = 7 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint16String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - code.mask = math.MaxUint16 - code.rshiftNum = 15 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint32String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - code.mask = math.MaxUint32 - code.rshiftNum = 31 - ctx.incIndex() - return code, nil -} - -func encodeCompileUint64String(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opUintString) - code.mask = math.MaxUint64 - code.rshiftNum = 63 - ctx.incIndex() - return code, nil -} - -func encodeCompileFloat32(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opFloat32) - ctx.incIndex() - return code, nil -} - -func encodeCompileFloat64(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opFloat64) - ctx.incIndex() - return code, nil -} - -func encodeCompileString(ctx *encodeCompileContext) (*opcode, error) { - var op opType - if ctx.typ == type2rtype(jsonNumberType) { - op = opNumber - } else { - op = opString - } - code := newOpCode(ctx, op) - ctx.incIndex() - return code, nil -} - -func encodeCompileBool(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opBool) - ctx.incIndex() - return code, nil -} - -func encodeCompileBytes(ctx *encodeCompileContext) (*opcode, error) { - code := newOpCode(ctx, opBytes) - ctx.incIndex() - return code, nil -} - -func encodeCompileInterface(ctx *encodeCompileContext) (*opcode, error) { - code := newInterfaceCode(ctx) - ctx.incIndex() - return code, nil -} - -func encodeCompileSlice(ctx *encodeCompileContext) (*opcode, error) { - elem := ctx.typ.Elem() - size := elem.Size() - - header := newSliceHeaderCode(ctx) - ctx.incIndex() - - code, err := encodeCompileSliceElem(ctx.withType(elem).incIndent()) - if err != nil { - return nil, err - } - - // header => opcode => elem => end - // ^ | - // |________| - - elemCode := newSliceElemCode(ctx, header, size) - ctx.incIndex() - - end := newOpCode(ctx, opSliceEnd) - ctx.incIndex() - - header.elem = elemCode - header.end = end - header.next = code - code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode)) - elemCode.next = code - elemCode.end = end - return (*opcode)(unsafe.Pointer(header)), nil -} - -func encodeCompileSliceElem(ctx *encodeCompileContext) (*opcode, error) { - typ := ctx.typ - switch { - case !typ.Implements(marshalJSONType) && rtype_ptrTo(typ).Implements(marshalJSONType): - return encodeCompileMarshalJSON(ctx) - case !typ.Implements(marshalTextType) && rtype_ptrTo(typ).Implements(marshalTextType): - return encodeCompileMarshalText(ctx) - default: - return encodeCompile(ctx, false) - } -} - -func encodeCompileArray(ctx *encodeCompileContext) (*opcode, error) { - typ := ctx.typ - elem := typ.Elem() - alen := typ.Len() - size := elem.Size() - - header := newArrayHeaderCode(ctx, alen) - ctx.incIndex() - - code, err := encodeCompile(ctx.withType(elem).incIndent(), false) - if err != nil { - return nil, err - } - // header => opcode => elem => end - // ^ | - // |________| - - elemCode := newArrayElemCode(ctx, header, alen, size) - ctx.incIndex() - - end := newOpCode(ctx, opArrayEnd) - ctx.incIndex() - - header.elem = elemCode - header.end = end - header.next = code - code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode)) - elemCode.next = code - elemCode.end = end - return (*opcode)(unsafe.Pointer(header)), nil -} - -//go:linkname mapiterinit reflect.mapiterinit -//go:noescape -func mapiterinit(mapType *rtype, m unsafe.Pointer) unsafe.Pointer - -//go:linkname mapiterkey reflect.mapiterkey -//go:noescape -func mapiterkey(it unsafe.Pointer) unsafe.Pointer - -//go:linkname mapiternext reflect.mapiternext -//go:noescape -func mapiternext(it unsafe.Pointer) - -//go:linkname maplen reflect.maplen -//go:noescape -func maplen(m unsafe.Pointer) int - -func encodeCompileMap(ctx *encodeCompileContext) (*opcode, error) { - // header => code => value => code => key => code => value => code => end - // ^ | - // |_______________________| - ctx = ctx.incIndent() - header := newMapHeaderCode(ctx) - ctx.incIndex() - - typ := ctx.typ - keyType := ctx.typ.Key() - keyCode, err := encodeCompileKey(ctx.withType(keyType)) - if err != nil { - return nil, err - } - - value := newMapValueCode(ctx, header) - ctx.incIndex() - - valueCode, err := encodeCompileMapValue(ctx.withType(typ.Elem())) - if err != nil { - return nil, err - } - - key := newMapKeyCode(ctx, header) - ctx.incIndex() - - ctx = ctx.decIndent() - - header.mapKey = key - header.mapValue = value - - end := newMapEndCode(ctx, header) - ctx.incIndex() - - header.next = keyCode - keyCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(value)) - value.next = valueCode - valueCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(key)) - key.next = keyCode - - header.end = end - key.end = end - value.end = end - - return (*opcode)(unsafe.Pointer(header)), nil -} - -func encodeCompileMapValue(ctx *encodeCompileContext) (*opcode, error) { - switch ctx.typ.Kind() { - case reflect.Map: - return encodeCompilePtr(ctx.withType(rtype_ptrTo(ctx.typ))) - default: - return encodeCompile(ctx, false) - } -} - -func encodeTypeToHeaderType(code *opcode) opType { - switch code.op { - case opInt: - return opStructFieldHeadInt - case opIntPtr: - return opStructFieldHeadIntPtr - case opUint: - return opStructFieldHeadUint - case opUintPtr: - return opStructFieldHeadUintPtr - case opFloat32: - return opStructFieldHeadFloat32 - case opFloat32Ptr: - return opStructFieldHeadFloat32Ptr - case opFloat64: - return opStructFieldHeadFloat64 - case opFloat64Ptr: - return opStructFieldHeadFloat64Ptr - case opString: - return opStructFieldHeadString - case opStringPtr: - return opStructFieldHeadStringPtr - case opNumber: - return opStructFieldHeadNumber - case opNumberPtr: - return opStructFieldHeadNumberPtr - case opBool: - return opStructFieldHeadBool - case opBoolPtr: - return opStructFieldHeadBoolPtr - case opMap: - return opStructFieldHeadMap - case opMapPtr: - code.op = opMap - return opStructFieldHeadMapPtr - case opArray: - return opStructFieldHeadArray - case opArrayPtr: - code.op = opArray - return opStructFieldHeadArrayPtr - case opSlice: - return opStructFieldHeadSlice - case opSlicePtr: - code.op = opSlice - return opStructFieldHeadSlicePtr - case opMarshalJSON: - return opStructFieldHeadMarshalJSON - case opMarshalJSONPtr: - return opStructFieldHeadMarshalJSONPtr - case opMarshalText: - return opStructFieldHeadMarshalText - case opMarshalTextPtr: - return opStructFieldHeadMarshalTextPtr - } - return opStructFieldHead -} - -func encodeTypeToFieldType(code *opcode) opType { - switch code.op { - case opInt: - return opStructFieldInt - case opIntPtr: - return opStructFieldIntPtr - case opUint: - return opStructFieldUint - case opUintPtr: - return opStructFieldUintPtr - case opFloat32: - return opStructFieldFloat32 - case opFloat32Ptr: - return opStructFieldFloat32Ptr - case opFloat64: - return opStructFieldFloat64 - case opFloat64Ptr: - return opStructFieldFloat64Ptr - case opString: - return opStructFieldString - case opStringPtr: - return opStructFieldStringPtr - case opNumber: - return opStructFieldNumber - case opNumberPtr: - return opStructFieldNumberPtr - case opBool: - return opStructFieldBool - case opBoolPtr: - return opStructFieldBoolPtr - case opMap: - return opStructFieldMap - case opMapPtr: - code.op = opMap - return opStructFieldMapPtr - case opArray: - return opStructFieldArray - case opArrayPtr: - code.op = opArray - return opStructFieldArrayPtr - case opSlice: - return opStructFieldSlice - case opSlicePtr: - code.op = opSlice - return opStructFieldSlicePtr - case opMarshalJSON: - return opStructFieldMarshalJSON - case opMarshalJSONPtr: - return opStructFieldMarshalJSONPtr - case opMarshalText: - return opStructFieldMarshalText - case opMarshalTextPtr: - return opStructFieldMarshalTextPtr - } - return opStructField -} - -func encodeOptimizeStructHeader(code *opcode, tag *structTag) opType { - headType := encodeTypeToHeaderType(code) - switch { - case tag.isOmitEmpty: - headType = headType.headToOmitEmptyHead() - case tag.isString: - headType = headType.headToStringTagHead() - } - return headType -} - -func encodeOptimizeStructField(code *opcode, tag *structTag) opType { - fieldType := encodeTypeToFieldType(code) - switch { - case tag.isOmitEmpty: - fieldType = fieldType.fieldToOmitEmptyField() - case tag.isString: - fieldType = fieldType.fieldToStringTagField() - } - return fieldType -} - -func encodeRecursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode { - code := newRecursiveCode(ctx, jmp) - ctx.incIndex() - return code -} - -func encodeCompiledCode(ctx *encodeCompileContext) *opcode { - typ := ctx.typ - typeptr := uintptr(unsafe.Pointer(typ)) - if compiledCode, exists := ctx.structTypeToCompiledCode[typeptr]; exists { - return encodeRecursiveCode(ctx, compiledCode) - } - return nil -} - -func encodeStructHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode { - fieldCode.indent-- - op := encodeOptimizeStructHeader(valueCode, tag) - fieldCode.op = op - fieldCode.mask = valueCode.mask - fieldCode.rshiftNum = valueCode.rshiftNum - fieldCode.ptrNum = valueCode.ptrNum - switch op { - case opStructFieldHead, - opStructFieldHeadSlice, - opStructFieldHeadArray, - opStructFieldHeadMap, - opStructFieldHeadStruct, - opStructFieldHeadOmitEmpty, - opStructFieldHeadOmitEmptySlice, - opStructFieldHeadStringTagSlice, - opStructFieldHeadOmitEmptyArray, - opStructFieldHeadStringTagArray, - opStructFieldHeadOmitEmptyMap, - opStructFieldHeadStringTagMap, - opStructFieldHeadOmitEmptyStruct, - opStructFieldHeadStringTag: - return valueCode.beforeLastCode() - case opStructFieldHeadSlicePtr, - opStructFieldHeadOmitEmptySlicePtr, - opStructFieldHeadStringTagSlicePtr, - opStructFieldHeadArrayPtr, - opStructFieldHeadOmitEmptyArrayPtr, - opStructFieldHeadStringTagArrayPtr, - opStructFieldHeadMapPtr, - opStructFieldHeadOmitEmptyMapPtr, - opStructFieldHeadStringTagMapPtr: - return valueCode.beforeLastCode() - case opStructFieldHeadMarshalJSONPtr, - opStructFieldHeadOmitEmptyMarshalJSONPtr, - opStructFieldHeadStringTagMarshalJSONPtr, - opStructFieldHeadMarshalTextPtr, - opStructFieldHeadOmitEmptyMarshalTextPtr, - opStructFieldHeadStringTagMarshalTextPtr: - ctx.decOpcodeIndex() - return (*opcode)(unsafe.Pointer(fieldCode)) - } - ctx.decOpcodeIndex() - return (*opcode)(unsafe.Pointer(fieldCode)) -} - -func encodeStructField(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode { - code := (*opcode)(unsafe.Pointer(fieldCode)) - op := encodeOptimizeStructField(valueCode, tag) - fieldCode.op = op - fieldCode.ptrNum = valueCode.ptrNum - fieldCode.mask = valueCode.mask - fieldCode.rshiftNum = valueCode.rshiftNum - fieldCode.jmp = valueCode.jmp - switch op { - case opStructField, - opStructFieldSlice, - opStructFieldArray, - opStructFieldMap, - opStructFieldStruct, - opStructFieldOmitEmpty, - opStructFieldOmitEmptySlice, - opStructFieldStringTagSlice, - opStructFieldOmitEmptyArray, - opStructFieldStringTagArray, - opStructFieldOmitEmptyMap, - opStructFieldStringTagMap, - opStructFieldOmitEmptyStruct, - opStructFieldStringTag: - return valueCode.beforeLastCode() - case opStructFieldSlicePtr, - opStructFieldOmitEmptySlicePtr, - opStructFieldStringTagSlicePtr, - opStructFieldArrayPtr, - opStructFieldOmitEmptyArrayPtr, - opStructFieldStringTagArrayPtr, - opStructFieldMapPtr, - opStructFieldOmitEmptyMapPtr, - opStructFieldStringTagMapPtr: - return valueCode.beforeLastCode() - } - ctx.decIndex() - return code -} - -func encodeIsNotExistsField(head *opcode) bool { - if head == nil { - return false - } - if head.op != opStructFieldHead { - return false - } - if !head.anonymousHead { - return false - } - if head.next == nil { - return false - } - if head.nextField == nil { - return false - } - if head.nextField.op != opStructAnonymousEnd { - return false - } - if head.next.op == opStructAnonymousEnd { - return true - } - if head.next.op.codeType() != codeStructField { - return false - } - return encodeIsNotExistsField(head.next) -} - -func encodeOptimizeAnonymousFields(head *opcode) { - code := head - var prev *opcode - removedFields := map[*opcode]struct{}{} - for { - if code.op == opStructEnd { - break - } - if code.op == opStructField { - codeType := code.next.op.codeType() - if codeType == codeStructField { - if encodeIsNotExistsField(code.next) { - code.next = code.nextField - diff := code.next.displayIdx - code.displayIdx - for i := 0; i < diff; i++ { - code.next.decOpcodeIndex() - } - encodeLinkPrevToNextField(code, removedFields) - code = prev - } - } - } - prev = code - code = code.nextField - } -} - -type structFieldPair struct { - prevField *opcode - curField *opcode - isTaggedKey bool - linked bool -} - -func encodeAnonymousStructFieldPairMap(tags structTags, named string, valueCode *opcode) map[string][]structFieldPair { - anonymousFields := map[string][]structFieldPair{} - f := valueCode - var prevAnonymousField *opcode - removedFields := map[*opcode]struct{}{} - for { - existsKey := tags.existsKey(f.displayKey) - isHeadOp := strings.Contains(f.op.String(), "Head") - if existsKey && strings.Contains(f.op.String(), "Recursive") { - // through - } else if isHeadOp && !f.anonymousHead { - if existsKey { - // TODO: need to remove this head - f.op = opStructFieldHead - f.anonymousKey = true - f.anonymousHead = true - } else if named == "" { - f.anonymousHead = true - } - } else if named == "" && f.op == opStructEnd { - f.op = opStructAnonymousEnd - } else if existsKey { - diff := f.nextField.displayIdx - f.displayIdx - for i := 0; i < diff; i++ { - f.nextField.decOpcodeIndex() - } - encodeLinkPrevToNextField(f, removedFields) - } - - if f.displayKey == "" { - if f.nextField == nil { - break - } - prevAnonymousField = f - f = f.nextField - continue - } - - key := fmt.Sprintf("%s.%s", named, f.displayKey) - anonymousFields[key] = append(anonymousFields[key], structFieldPair{ - prevField: prevAnonymousField, - curField: f, - isTaggedKey: f.isTaggedKey, - }) - if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField { - for k, v := range encodeAnonymousFieldPairRecursively(named, f.next) { - anonymousFields[k] = append(anonymousFields[k], v...) - } - } - if f.nextField == nil { - break - } - prevAnonymousField = f - f = f.nextField - } - return anonymousFields -} - -func encodeAnonymousFieldPairRecursively(named string, valueCode *opcode) map[string][]structFieldPair { - anonymousFields := map[string][]structFieldPair{} - f := valueCode - var prevAnonymousField *opcode - for { - if f.displayKey != "" && f.anonymousHead { - key := fmt.Sprintf("%s.%s", named, f.displayKey) - anonymousFields[key] = append(anonymousFields[key], structFieldPair{ - prevField: prevAnonymousField, - curField: f, - isTaggedKey: f.isTaggedKey, - }) - if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField { - for k, v := range encodeAnonymousFieldPairRecursively(named, f.next) { - anonymousFields[k] = append(anonymousFields[k], v...) - } - } - } - if f.nextField == nil { - break - } - prevAnonymousField = f - f = f.nextField - } - return anonymousFields -} - -func encodeOptimizeConflictAnonymousFields(anonymousFields map[string][]structFieldPair) { - removedFields := map[*opcode]struct{}{} - for _, fieldPairs := range anonymousFields { - if len(fieldPairs) == 1 { - continue - } - // conflict anonymous fields - taggedPairs := []structFieldPair{} - for _, fieldPair := range fieldPairs { - if fieldPair.isTaggedKey { - taggedPairs = append(taggedPairs, fieldPair) - } else { - if !fieldPair.linked { - if fieldPair.prevField == nil { - // head operation - fieldPair.curField.op = opStructFieldHead - fieldPair.curField.anonymousHead = true - fieldPair.curField.anonymousKey = true - } else { - diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx - for i := 0; i < diff; i++ { - fieldPair.curField.nextField.decOpcodeIndex() - } - removedFields[fieldPair.curField] = struct{}{} - encodeLinkPrevToNextField(fieldPair.curField, removedFields) - } - fieldPair.linked = true - } - } - } - if len(taggedPairs) > 1 { - for _, fieldPair := range taggedPairs { - if !fieldPair.linked { - if fieldPair.prevField == nil { - // head operation - fieldPair.curField.op = opStructFieldHead - fieldPair.curField.anonymousHead = true - fieldPair.curField.anonymousKey = true - } else { - diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx - removedFields[fieldPair.curField] = struct{}{} - for i := 0; i < diff; i++ { - fieldPair.curField.nextField.decOpcodeIndex() - } - encodeLinkPrevToNextField(fieldPair.curField, removedFields) - } - fieldPair.linked = true - } - } - } else { - for _, fieldPair := range taggedPairs { - fieldPair.curField.isTaggedKey = false - } - } - } -} - -func encodeIsNilableType(typ *rtype) bool { - switch typ.Kind() { - case reflect.Ptr: - return true - case reflect.Interface: - return true - case reflect.Slice: - return true - case reflect.Map: - return true - default: - return false - } -} - -func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error) { - if code := encodeCompiledCode(ctx); code != nil { - return code, nil - } - typ := ctx.typ - typeptr := uintptr(unsafe.Pointer(typ)) - compiled := &compiledCode{} - ctx.structTypeToCompiledCode[typeptr] = compiled - // header => code => structField => code => end - // ^ | - // |__________| - fieldNum := typ.NumField() - indirect := ifaceIndir(typ) - fieldIdx := 0 - disableIndirectConversion := false - var ( - head *opcode - code *opcode - prevField *opcode - ) - ctx = ctx.incIndent() - tags := structTags{} - anonymousFields := map[string][]structFieldPair{} - for i := 0; i < fieldNum; i++ { - field := typ.Field(i) - if isIgnoredStructField(field) { - continue - } - tags = append(tags, structTagFromField(field)) - } - for i, tag := range tags { - field := tag.field - fieldType := type2rtype(field.Type) - fieldOpcodeIndex := ctx.opcodeIndex - fieldPtrIndex := ctx.ptrIndex - ctx.incIndex() - - nilcheck := true - addrForMarshaler := false - isIndirectSpecialCase := isPtr && i == 0 && fieldNum == 1 - isNilableType := encodeIsNilableType(fieldType) - - var valueCode *opcode - switch { - case isIndirectSpecialCase && !isNilableType && encodeIsPtrMarshalJSONType(fieldType): - // *struct{ field T } => struct { field *T } - // func (*T) MarshalJSON() ([]byte, error) - // move pointer position from head to first field - code, err := encodeCompileMarshalJSON(ctx.withType(rtype_ptrTo(fieldType))) - if err != nil { - return nil, err - } - valueCode = code - nilcheck = false - indirect = false - disableIndirectConversion = true - case isIndirectSpecialCase && !isNilableType && encodeIsPtrMarshalTextType(fieldType): - // *struct{ field T } => struct { field *T } - // func (*T) MarshalText() ([]byte, error) - // move pointer position from head to first field - code, err := encodeCompileMarshalText(ctx.withType(rtype_ptrTo(fieldType))) - if err != nil { - return nil, err - } - valueCode = code - nilcheck = false - indirect = false - disableIndirectConversion = true - case isPtr && encodeIsPtrMarshalJSONType(fieldType): - // *struct{ field T } - // func (*T) MarshalJSON() ([]byte, error) - code, err := encodeCompileMarshalJSON(ctx.withType(fieldType)) - if err != nil { - return nil, err - } - addrForMarshaler = true - nilcheck = false - valueCode = code - case isPtr && encodeIsPtrMarshalTextType(fieldType): - // *struct{ field T } - // func (*T) MarshalText() ([]byte, error) - code, err := encodeCompileMarshalText(ctx.withType(fieldType)) - if err != nil { - return nil, err - } - addrForMarshaler = true - nilcheck = false - valueCode = code - default: - code, err := encodeCompile(ctx.withType(fieldType), isPtr) - if err != nil { - return nil, err - } - valueCode = code - } - - if field.Anonymous { - tagKey := "" - if tag.isTaggedKey { - tagKey = tag.key - } - for k, v := range encodeAnonymousStructFieldPairMap(tags, tagKey, valueCode) { - anonymousFields[k] = append(anonymousFields[k], v...) - } - valueCode.decIndent() - - // fix issue144 - if !(isPtr && strings.Contains(valueCode.op.String(), "Marshal")) { - valueCode.indirect = indirect - } - } else { - valueCode.indirect = indirect - } - key := fmt.Sprintf(`"%s":`, tag.key) - escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key))) - fieldCode := &opcode{ - typ: valueCode.typ, - displayIdx: fieldOpcodeIndex, - idx: opcodeOffset(fieldPtrIndex), - next: valueCode, - indent: ctx.indent, - anonymousKey: field.Anonymous, - key: []byte(key), - escapedKey: []byte(escapedKey), - isTaggedKey: tag.isTaggedKey, - displayKey: tag.key, - offset: field.Offset, - indirect: indirect, - nilcheck: nilcheck, - addrForMarshaler: addrForMarshaler, - } - if fieldIdx == 0 { - fieldCode.headIdx = fieldCode.idx - code = encodeStructHeader(ctx, fieldCode, valueCode, tag) - head = fieldCode - prevField = fieldCode - } else { - fieldCode.headIdx = head.headIdx - code.next = fieldCode - code = encodeStructField(ctx, fieldCode, valueCode, tag) - prevField.nextField = fieldCode - fieldCode.prevField = prevField - prevField = fieldCode - } - fieldIdx++ - } - ctx = ctx.decIndent() - - structEndCode := &opcode{ - op: opStructEnd, - typ: nil, - indent: ctx.indent, - next: newEndOp(ctx), - } - - // no struct field - if head == nil { - head = &opcode{ - op: opStructFieldHead, - typ: typ, - displayIdx: ctx.opcodeIndex, - idx: opcodeOffset(ctx.ptrIndex), - headIdx: opcodeOffset(ctx.ptrIndex), - indent: ctx.indent, - nextField: structEndCode, - } - structEndCode.prevField = head - ctx.incIndex() - code = head - } - - structEndCode.displayIdx = ctx.opcodeIndex - structEndCode.idx = opcodeOffset(ctx.ptrIndex) - ctx.incIndex() - - if prevField != nil && prevField.nextField == nil { - prevField.nextField = structEndCode - structEndCode.prevField = prevField - } - - head.end = structEndCode - code.next = structEndCode - encodeOptimizeConflictAnonymousFields(anonymousFields) - encodeOptimizeAnonymousFields(head) - ret := (*opcode)(unsafe.Pointer(head)) - compiled.code = ret - - delete(ctx.structTypeToCompiledCode, typeptr) - - if !disableIndirectConversion && !head.indirect && isPtr { - head.indirect = true - } - - return ret, nil -} - -func encodeIsPtrMarshalJSONType(typ *rtype) bool { - return !typ.Implements(marshalJSONType) && rtype_ptrTo(typ).Implements(marshalJSONType) -} - -func encodeIsPtrMarshalTextType(typ *rtype) bool { - return !typ.Implements(marshalTextType) && rtype_ptrTo(typ).Implements(marshalTextType) -} diff --git a/encode_compile_norace.go b/encode_compile_norace.go deleted file mode 100644 index 3305a5b..0000000 --- a/encode_compile_norace.go +++ /dev/null @@ -1,34 +0,0 @@ -// +build !race - -package json - -import "unsafe" - -func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) { - if typeptr > maxTypeAddr { - return encodeCompileToGetCodeSetSlowPath(typeptr) - } - index := typeptr - baseTypeAddr - if codeSet := cachedOpcodeSets[index]; codeSet != nil { - return codeSet, nil - } - - // noescape trick for header.typ ( reflect.*rtype ) - copiedType := *(**rtype)(unsafe.Pointer(&typeptr)) - - code, err := encodeCompileHead(&encodeCompileContext{ - typ: copiedType, - structTypeToCompiledCode: map[uintptr]*compiledCode{}, - }) - if err != nil { - return nil, err - } - code = copyOpcode(code) - codeLength := code.totalLength() - codeSet := &opcodeSet{ - code: code, - codeLength: codeLength, - } - cachedOpcodeSets[index] = codeSet - return codeSet, nil -} diff --git a/encode_compile_race.go b/encode_compile_race.go deleted file mode 100644 index decba6e..0000000 --- a/encode_compile_race.go +++ /dev/null @@ -1,44 +0,0 @@ -// +build race - -package json - -import ( - "sync" - "unsafe" -) - -var setsMu sync.RWMutex - -func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) { - if typeptr > maxTypeAddr { - return encodeCompileToGetCodeSetSlowPath(typeptr) - } - index := typeptr - baseTypeAddr - setsMu.RLock() - if codeSet := cachedOpcodeSets[index]; codeSet != nil { - setsMu.RUnlock() - return codeSet, nil - } - setsMu.RUnlock() - - // noescape trick for header.typ ( reflect.*rtype ) - copiedType := *(**rtype)(unsafe.Pointer(&typeptr)) - - code, err := encodeCompileHead(&encodeCompileContext{ - typ: copiedType, - structTypeToCompiledCode: map[uintptr]*compiledCode{}, - }) - if err != nil { - return nil, err - } - code = copyOpcode(code) - codeLength := code.totalLength() - codeSet := &opcodeSet{ - code: code, - codeLength: codeLength, - } - setsMu.Lock() - cachedOpcodeSets[index] = codeSet - setsMu.Unlock() - return codeSet, nil -} diff --git a/encode_context.go b/encode_context.go deleted file mode 100644 index 9d45f1e..0000000 --- a/encode_context.go +++ /dev/null @@ -1,164 +0,0 @@ -package json - -import ( - "bytes" - "sync" - "unsafe" -) - -type mapItem struct { - key []byte - value []byte -} - -type mapslice struct { - items []mapItem -} - -func (m *mapslice) Len() int { - return len(m.items) -} - -func (m *mapslice) Less(i, j int) bool { - return bytes.Compare(m.items[i].key, m.items[j].key) < 0 -} - -func (m *mapslice) Swap(i, j int) { - m.items[i], m.items[j] = m.items[j], m.items[i] -} - -type encodeMapContext struct { - pos []int - slice *mapslice - buf []byte -} - -var mapContextPool = sync.Pool{ - New: func() interface{} { - return &encodeMapContext{} - }, -} - -func newMapContext(mapLen int) *encodeMapContext { - ctx := mapContextPool.Get().(*encodeMapContext) - if ctx.slice == nil { - ctx.slice = &mapslice{ - items: make([]mapItem, 0, mapLen), - } - } - if cap(ctx.pos) < (mapLen*2 + 1) { - ctx.pos = make([]int, 0, mapLen*2+1) - ctx.slice.items = make([]mapItem, 0, mapLen) - } else { - ctx.pos = ctx.pos[:0] - ctx.slice.items = ctx.slice.items[:0] - } - ctx.buf = ctx.buf[:0] - return ctx -} - -func releaseMapContext(c *encodeMapContext) { - mapContextPool.Put(c) -} - -type encodeCompileContext struct { - typ *rtype - opcodeIndex int - ptrIndex int - indent int - structTypeToCompiledCode map[uintptr]*compiledCode - - parent *encodeCompileContext -} - -func (c *encodeCompileContext) context() *encodeCompileContext { - return &encodeCompileContext{ - typ: c.typ, - opcodeIndex: c.opcodeIndex, - ptrIndex: c.ptrIndex, - indent: c.indent, - structTypeToCompiledCode: c.structTypeToCompiledCode, - parent: c, - } -} - -func (c *encodeCompileContext) withType(typ *rtype) *encodeCompileContext { - ctx := c.context() - ctx.typ = typ - return ctx -} - -func (c *encodeCompileContext) incIndent() *encodeCompileContext { - ctx := c.context() - ctx.indent++ - return ctx -} - -func (c *encodeCompileContext) decIndent() *encodeCompileContext { - ctx := c.context() - ctx.indent-- - return ctx -} - -func (c *encodeCompileContext) incIndex() { - c.incOpcodeIndex() - c.incPtrIndex() -} - -func (c *encodeCompileContext) decIndex() { - c.decOpcodeIndex() - c.decPtrIndex() -} - -func (c *encodeCompileContext) incOpcodeIndex() { - c.opcodeIndex++ - if c.parent != nil { - c.parent.incOpcodeIndex() - } -} - -func (c *encodeCompileContext) decOpcodeIndex() { - c.opcodeIndex-- - if c.parent != nil { - c.parent.decOpcodeIndex() - } -} - -func (c *encodeCompileContext) incPtrIndex() { - c.ptrIndex++ - if c.parent != nil { - c.parent.incPtrIndex() - } -} - -func (c *encodeCompileContext) decPtrIndex() { - c.ptrIndex-- - if c.parent != nil { - c.parent.decPtrIndex() - } -} - -type encodeRuntimeContext struct { - buf []byte - ptrs []uintptr - keepRefs []unsafe.Pointer - seenPtr []uintptr - baseIndent int - prefix []byte - indentStr []byte -} - -func (c *encodeRuntimeContext) init(p uintptr, codelen int) { - if len(c.ptrs) < codelen { - c.ptrs = make([]uintptr, codelen) - } - c.ptrs[0] = p - c.keepRefs = c.keepRefs[:0] - c.seenPtr = c.seenPtr[:0] - c.baseIndent = 0 -} - -func (c *encodeRuntimeContext) ptr() uintptr { - header := (*sliceHeader)(unsafe.Pointer(&c.ptrs)) - return uintptr(header.data) -} diff --git a/encode_int.go b/encode_int.go deleted file mode 100644 index 993b9d1..0000000 --- a/encode_int.go +++ /dev/null @@ -1,124 +0,0 @@ -package json - -import ( - "unsafe" -) - -var endianness int - -func init() { - var b [2]byte - *(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD) - - switch b[0] { - case 0xCD: - endianness = 0 // LE - case 0xAB: - endianness = 1 // BE - default: - panic("could not determine endianness") - } -} - -// "00010203...96979899" cast to []uint16 -var intLELookup = [100]uint16{ - 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, - 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, - 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, - 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, - 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, - 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, - 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, - 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, - 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, - 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939, -} - -var intBELookup = [100]uint16{ - 0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039, - 0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139, - 0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239, - 0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339, - 0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439, - 0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539, - 0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639, - 0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739, - 0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839, - 0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939, -} - -var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup} - -func appendInt(out []byte, u64 uint64, code *opcode) []byte { - n := u64 & code.mask - negative := (u64>>code.rshiftNum)&1 == 1 - if !negative { - if n < 10 { - return append(out, byte(n+'0')) - } else if n < 100 { - u := intLELookup[n] - return append(out, byte(u), byte(u>>8)) - } - } else { - n = -n & code.mask - } - - lookup := intLookup[endianness] - - var b [22]byte - u := (*[11]uint16)(unsafe.Pointer(&b)) - i := 11 - - for n >= 100 { - j := n % 100 - n /= 100 - i-- - u[i] = lookup[j] - } - - i-- - u[i] = lookup[n] - - i *= 2 // convert to byte index - if n < 10 { - i++ // remove leading zero - } - if negative { - i-- - b[i] = '-' - } - - return append(out, b[i:]...) -} - -func appendUint(out []byte, u64 uint64, code *opcode) []byte { - n := u64 & code.mask - if n < 10 { - return append(out, byte(n+'0')) - } else if n < 100 { - u := intLELookup[n] - return append(out, byte(u), byte(u>>8)) - } - - lookup := intLookup[endianness] - - var b [22]byte - u := (*[11]uint16)(unsafe.Pointer(&b)) - i := 11 - - for n >= 100 { - j := n % 100 - n /= 100 - i-- - u[i] = lookup[j] - } - - i-- - u[i] = lookup[n] - - i *= 2 // convert to byte index - if n < 10 { - i++ // remove leading zero - } - return append(out, b[i:]...) -} diff --git a/encode_map112.go b/encode_map112.go deleted file mode 100644 index 99b4bdb..0000000 --- a/encode_map112.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !go1.13 - -package json - -import "unsafe" - -//go:linkname mapitervalue reflect.mapitervalue -func mapitervalue(it unsafe.Pointer) unsafe.Pointer diff --git a/encode_map113.go b/encode_map113.go deleted file mode 100644 index 48bbd6d..0000000 --- a/encode_map113.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build go1.13 - -package json - -import "unsafe" - -//go:linkname mapitervalue reflect.mapiterelem -func mapitervalue(it unsafe.Pointer) unsafe.Pointer diff --git a/encode_opcode.go b/encode_opcode.go deleted file mode 100644 index 1278f12..0000000 --- a/encode_opcode.go +++ /dev/null @@ -1,512 +0,0 @@ -package json - -import ( - "fmt" - "strings" - "unsafe" -) - -const uintptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const - -type opcode struct { - op opType // operation type - typ *rtype // go type - displayIdx int // opcode index - key []byte // struct field key - escapedKey []byte // struct field key ( HTML escaped ) - ptrNum int // pointer number: e.g. double pointer is 2. - displayKey string // key text to display - isTaggedKey bool // whether tagged key - anonymousKey bool // whether anonymous key - anonymousHead bool // whether anonymous head or not - indirect bool // whether indirect or not - nilcheck bool // whether needs to nilcheck or not - addrForMarshaler bool // whether needs to addr for marshaler or not - rshiftNum uint8 // use to take bit for judging whether negative integer or not - mask uint64 // mask for number - indent int // indent number - - idx uintptr // offset to access ptr - headIdx uintptr // offset to access slice/struct head - elemIdx uintptr // offset to access array/slice/map elem - length uintptr // offset to access slice/map length or array length - mapIter uintptr // offset to access map iterator - mapPos uintptr // offset to access position list for sorted map - offset uintptr // offset size from struct header - size uintptr // array/slice elem size - - mapKey *opcode // map key - mapValue *opcode // map value - elem *opcode // array/slice elem - end *opcode // array/slice/struct/map end - prevField *opcode // prev struct field - nextField *opcode // next struct field - next *opcode // next opcode - jmp *compiledCode // for recursive call -} - -func newOpCode(ctx *encodeCompileContext, op opType) *opcode { - return newOpCodeWithNext(ctx, op, newEndOp(ctx)) -} - -func opcodeOffset(idx int) uintptr { - return uintptr(idx) * uintptrSize -} - -func copyOpcode(code *opcode) *opcode { - codeMap := map[uintptr]*opcode{} - return code.copy(codeMap) -} - -func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode { - return &opcode{ - op: op, - typ: ctx.typ, - displayIdx: ctx.opcodeIndex, - indent: ctx.indent, - idx: opcodeOffset(ctx.ptrIndex), - next: next, - } -} - -func newEndOp(ctx *encodeCompileContext) *opcode { - return newOpCodeWithNext(ctx, opEnd, nil) -} - -func (c *opcode) copy(codeMap map[uintptr]*opcode) *opcode { - if c == nil { - return nil - } - addr := uintptr(unsafe.Pointer(c)) - if code, exists := codeMap[addr]; exists { - return code - } - copied := &opcode{ - op: c.op, - typ: c.typ, - displayIdx: c.displayIdx, - key: c.key, - escapedKey: c.escapedKey, - displayKey: c.displayKey, - ptrNum: c.ptrNum, - mask: c.mask, - rshiftNum: c.rshiftNum, - isTaggedKey: c.isTaggedKey, - anonymousKey: c.anonymousKey, - anonymousHead: c.anonymousHead, - indirect: c.indirect, - nilcheck: c.nilcheck, - addrForMarshaler: c.addrForMarshaler, - indent: c.indent, - idx: c.idx, - headIdx: c.headIdx, - elemIdx: c.elemIdx, - length: c.length, - mapIter: c.mapIter, - mapPos: c.mapPos, - offset: c.offset, - size: c.size, - } - codeMap[addr] = copied - copied.mapKey = c.mapKey.copy(codeMap) - copied.mapValue = c.mapValue.copy(codeMap) - copied.elem = c.elem.copy(codeMap) - copied.end = c.end.copy(codeMap) - copied.prevField = c.prevField.copy(codeMap) - copied.nextField = c.nextField.copy(codeMap) - copied.next = c.next.copy(codeMap) - copied.jmp = c.jmp - return copied -} - -func (c *opcode) beforeLastCode() *opcode { - code := c - for { - var nextCode *opcode - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - nextCode = code.end - default: - nextCode = code.next - } - if nextCode.op == opEnd { - return code - } - code = nextCode - } -} - -func (c *opcode) totalLength() int { - var idx int - for code := c; code.op != opEnd; { - idx = int(code.idx / uintptrSize) - if code.op == opStructFieldRecursiveEnd { - break - } - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - default: - code = code.next - } - } - return idx + 2 // opEnd + 1 -} - -func (c *opcode) decOpcodeIndex() { - for code := c; code.op != opEnd; { - code.displayIdx-- - code.idx -= uintptrSize - if code.headIdx > 0 { - code.headIdx -= uintptrSize - } - if code.elemIdx > 0 { - code.elemIdx -= uintptrSize - } - if code.mapIter > 0 { - code.mapIter -= uintptrSize - } - if code.length > 0 && code.op.codeType() != codeArrayHead && code.op.codeType() != codeArrayElem { - code.length -= uintptrSize - } - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - default: - code = code.next - } - } -} - -func (c *opcode) decIndent() { - for code := c; code.op != opEnd; { - code.indent-- - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - code = code.end - default: - code = code.next - } - } -} - -func (c *opcode) dumpHead(code *opcode) string { - var length uintptr - if code.op.codeType() == codeArrayHead { - length = code.length - } else { - length = code.length / uintptrSize - } - return fmt.Sprintf( - `[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d])`, - code.displayIdx, - strings.Repeat("-", code.indent), - code.op, - code.idx/uintptrSize, - code.headIdx/uintptrSize, - code.elemIdx/uintptrSize, - length, - ) -} - -func (c *opcode) dumpMapHead(code *opcode) string { - return fmt.Sprintf( - `[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][mapIter:%d])`, - code.displayIdx, - strings.Repeat("-", code.indent), - code.op, - code.idx/uintptrSize, - code.headIdx/uintptrSize, - code.elemIdx/uintptrSize, - code.length/uintptrSize, - code.mapIter/uintptrSize, - ) -} - -func (c *opcode) dumpMapEnd(code *opcode) string { - return fmt.Sprintf( - `[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`, - code.displayIdx, - strings.Repeat("-", code.indent), - code.op, - code.idx/uintptrSize, - code.mapPos/uintptrSize, - code.length/uintptrSize, - ) -} - -func (c *opcode) dumpElem(code *opcode) string { - var length uintptr - if code.op.codeType() == codeArrayElem { - length = code.length - } else { - length = code.length / uintptrSize - } - return fmt.Sprintf( - `[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][size:%d])`, - code.displayIdx, - strings.Repeat("-", code.indent), - code.op, - code.idx/uintptrSize, - code.headIdx/uintptrSize, - code.elemIdx/uintptrSize, - length, - code.size, - ) -} - -func (c *opcode) dumpField(code *opcode) string { - return fmt.Sprintf( - `[%d]%s%s ([idx:%d][key:%s][offset:%d][headIdx:%d])`, - code.displayIdx, - strings.Repeat("-", code.indent), - code.op, - code.idx/uintptrSize, - code.displayKey, - code.offset, - code.headIdx/uintptrSize, - ) -} - -func (c *opcode) dumpKey(code *opcode) string { - return fmt.Sprintf( - `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, - code.displayIdx, - strings.Repeat("-", code.indent), - code.op, - code.idx/uintptrSize, - code.elemIdx/uintptrSize, - code.length/uintptrSize, - code.mapIter/uintptrSize, - ) -} - -func (c *opcode) dumpValue(code *opcode) string { - return fmt.Sprintf( - `[%d]%s%s ([idx:%d][mapIter:%d])`, - code.displayIdx, - strings.Repeat("-", code.indent), - code.op, - code.idx/uintptrSize, - code.mapIter/uintptrSize, - ) -} - -func (c *opcode) dump() string { - codes := []string{} - for code := c; code.op != opEnd; { - switch code.op.codeType() { - case codeSliceHead: - codes = append(codes, c.dumpHead(code)) - code = code.next - case codeMapHead: - codes = append(codes, c.dumpMapHead(code)) - code = code.next - case codeArrayElem, codeSliceElem: - codes = append(codes, c.dumpElem(code)) - code = code.end - case codeMapKey: - codes = append(codes, c.dumpKey(code)) - code = code.end - case codeMapValue: - codes = append(codes, c.dumpValue(code)) - code = code.next - case codeMapEnd: - codes = append(codes, c.dumpMapEnd(code)) - code = code.next - case codeStructField: - codes = append(codes, c.dumpField(code)) - code = code.next - case codeStructEnd: - codes = append(codes, c.dumpField(code)) - code = code.next - default: - codes = append(codes, fmt.Sprintf( - "[%d]%s%s ([idx:%d])", - code.displayIdx, - strings.Repeat("-", code.indent), - code.op, - code.idx/uintptrSize, - )) - code = code.next - } - } - return strings.Join(codes, "\n") -} - -func prevField(code *opcode, removedFields map[*opcode]struct{}) *opcode { - if _, exists := removedFields[code]; exists { - return prevField(code.prevField, removedFields) - } - return code -} - -func nextField(code *opcode, removedFields map[*opcode]struct{}) *opcode { - if _, exists := removedFields[code]; exists { - return nextField(code.nextField, removedFields) - } - return code -} - -func encodeLinkPrevToNextField(cur *opcode, removedFields map[*opcode]struct{}) { - prev := prevField(cur.prevField, removedFields) - prev.nextField = nextField(cur.nextField, removedFields) - code := prev - fcode := cur - for { - var nextCode *opcode - switch code.op.codeType() { - case codeArrayElem, codeSliceElem, codeMapKey: - nextCode = code.end - default: - nextCode = code.next - } - if nextCode == fcode { - code.next = fcode.next - break - } else if nextCode.op == opEnd { - break - } - code = nextCode - } -} - -func newSliceHeaderCode(ctx *encodeCompileContext) *opcode { - idx := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - elemIdx := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - length := opcodeOffset(ctx.ptrIndex) - return &opcode{ - op: opSlice, - displayIdx: ctx.opcodeIndex, - idx: idx, - headIdx: idx, - elemIdx: elemIdx, - length: length, - indent: ctx.indent, - } -} - -func newSliceElemCode(ctx *encodeCompileContext, head *opcode, size uintptr) *opcode { - return &opcode{ - op: opSliceElem, - displayIdx: ctx.opcodeIndex, - idx: opcodeOffset(ctx.ptrIndex), - headIdx: head.idx, - elemIdx: head.elemIdx, - length: head.length, - indent: ctx.indent, - size: size, - } -} - -func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *opcode { - idx := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - elemIdx := opcodeOffset(ctx.ptrIndex) - return &opcode{ - op: opArray, - displayIdx: ctx.opcodeIndex, - idx: idx, - headIdx: idx, - elemIdx: elemIdx, - indent: ctx.indent, - length: uintptr(alen), - } -} - -func newArrayElemCode(ctx *encodeCompileContext, head *opcode, length int, size uintptr) *opcode { - return &opcode{ - op: opArrayElem, - displayIdx: ctx.opcodeIndex, - idx: opcodeOffset(ctx.ptrIndex), - elemIdx: head.elemIdx, - headIdx: head.headIdx, - length: uintptr(length), - indent: ctx.indent, - size: size, - } -} - -func newMapHeaderCode(ctx *encodeCompileContext) *opcode { - idx := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - elemIdx := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - length := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - mapIter := opcodeOffset(ctx.ptrIndex) - return &opcode{ - op: opMap, - typ: ctx.typ, - displayIdx: ctx.opcodeIndex, - idx: idx, - elemIdx: elemIdx, - length: length, - mapIter: mapIter, - indent: ctx.indent, - } -} - -func newMapKeyCode(ctx *encodeCompileContext, head *opcode) *opcode { - return &opcode{ - op: opMapKey, - displayIdx: ctx.opcodeIndex, - idx: opcodeOffset(ctx.ptrIndex), - elemIdx: head.elemIdx, - length: head.length, - mapIter: head.mapIter, - indent: ctx.indent, - } -} - -func newMapValueCode(ctx *encodeCompileContext, head *opcode) *opcode { - return &opcode{ - op: opMapValue, - displayIdx: ctx.opcodeIndex, - idx: opcodeOffset(ctx.ptrIndex), - elemIdx: head.elemIdx, - length: head.length, - mapIter: head.mapIter, - indent: ctx.indent, - } -} - -func newMapEndCode(ctx *encodeCompileContext, head *opcode) *opcode { - mapPos := opcodeOffset(ctx.ptrIndex) - ctx.incPtrIndex() - idx := opcodeOffset(ctx.ptrIndex) - return &opcode{ - op: opMapEnd, - displayIdx: ctx.opcodeIndex, - idx: idx, - length: head.length, - mapPos: mapPos, - indent: ctx.indent, - next: newEndOp(ctx), - } -} - -func newInterfaceCode(ctx *encodeCompileContext) *opcode { - return &opcode{ - op: opInterface, - typ: ctx.typ, - displayIdx: ctx.opcodeIndex, - idx: opcodeOffset(ctx.ptrIndex), - indent: ctx.indent, - next: newEndOp(ctx), - } -} - -func newRecursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode { - return &opcode{ - op: opStructFieldRecursive, - typ: ctx.typ, - displayIdx: ctx.opcodeIndex, - idx: opcodeOffset(ctx.ptrIndex), - indent: ctx.indent, - next: newEndOp(ctx), - jmp: jmp, - } -} diff --git a/encode_optype.go b/encode_optype.go deleted file mode 100644 index 7e73479..0000000 --- a/encode_optype.go +++ /dev/null @@ -1,1186 +0,0 @@ -// Code generated by cmd/generator. DO NOT EDIT! -package json - -import ( - "strings" -) - -type codeType int - -const ( - codeOp codeType = 0 - codeArrayHead codeType = 1 - codeArrayElem codeType = 2 - codeSliceHead codeType = 3 - codeSliceElem codeType = 4 - codeMapHead codeType = 5 - codeMapKey codeType = 6 - codeMapValue codeType = 7 - codeMapEnd codeType = 8 - codeStructFieldRecursive codeType = 9 - codeStructField codeType = 10 - codeStructEnd codeType = 11 -) - -var opTypeStrings = [440]string{ - "End", - "Interface", - "Ptr", - "SliceElem", - "SliceEnd", - "ArrayElem", - "ArrayEnd", - "MapKey", - "MapValue", - "MapEnd", - "StructFieldRecursiveEnd", - "StructAnonymousEnd", - "Int", - "Uint", - "Float32", - "Float64", - "Bool", - "String", - "Bytes", - "Number", - "Array", - "Map", - "Slice", - "Struct", - "MarshalJSON", - "MarshalText", - "Recursive", - "IntString", - "UintString", - "IntPtr", - "UintPtr", - "Float32Ptr", - "Float64Ptr", - "BoolPtr", - "StringPtr", - "BytesPtr", - "NumberPtr", - "ArrayPtr", - "MapPtr", - "SlicePtr", - "MarshalJSONPtr", - "MarshalTextPtr", - "InterfacePtr", - "RecursivePtr", - "StructFieldHeadInt", - "StructFieldHeadOmitEmptyInt", - "StructFieldHeadStringTagInt", - "StructFieldPtrHeadInt", - "StructFieldPtrHeadOmitEmptyInt", - "StructFieldPtrHeadStringTagInt", - "StructFieldHeadUint", - "StructFieldHeadOmitEmptyUint", - "StructFieldHeadStringTagUint", - "StructFieldPtrHeadUint", - "StructFieldPtrHeadOmitEmptyUint", - "StructFieldPtrHeadStringTagUint", - "StructFieldHeadFloat32", - "StructFieldHeadOmitEmptyFloat32", - "StructFieldHeadStringTagFloat32", - "StructFieldPtrHeadFloat32", - "StructFieldPtrHeadOmitEmptyFloat32", - "StructFieldPtrHeadStringTagFloat32", - "StructFieldHeadFloat64", - "StructFieldHeadOmitEmptyFloat64", - "StructFieldHeadStringTagFloat64", - "StructFieldPtrHeadFloat64", - "StructFieldPtrHeadOmitEmptyFloat64", - "StructFieldPtrHeadStringTagFloat64", - "StructFieldHeadBool", - "StructFieldHeadOmitEmptyBool", - "StructFieldHeadStringTagBool", - "StructFieldPtrHeadBool", - "StructFieldPtrHeadOmitEmptyBool", - "StructFieldPtrHeadStringTagBool", - "StructFieldHeadString", - "StructFieldHeadOmitEmptyString", - "StructFieldHeadStringTagString", - "StructFieldPtrHeadString", - "StructFieldPtrHeadOmitEmptyString", - "StructFieldPtrHeadStringTagString", - "StructFieldHeadBytes", - "StructFieldHeadOmitEmptyBytes", - "StructFieldHeadStringTagBytes", - "StructFieldPtrHeadBytes", - "StructFieldPtrHeadOmitEmptyBytes", - "StructFieldPtrHeadStringTagBytes", - "StructFieldHeadNumber", - "StructFieldHeadOmitEmptyNumber", - "StructFieldHeadStringTagNumber", - "StructFieldPtrHeadNumber", - "StructFieldPtrHeadOmitEmptyNumber", - "StructFieldPtrHeadStringTagNumber", - "StructFieldHeadArray", - "StructFieldHeadOmitEmptyArray", - "StructFieldHeadStringTagArray", - "StructFieldPtrHeadArray", - "StructFieldPtrHeadOmitEmptyArray", - "StructFieldPtrHeadStringTagArray", - "StructFieldHeadMap", - "StructFieldHeadOmitEmptyMap", - "StructFieldHeadStringTagMap", - "StructFieldPtrHeadMap", - "StructFieldPtrHeadOmitEmptyMap", - "StructFieldPtrHeadStringTagMap", - "StructFieldHeadSlice", - "StructFieldHeadOmitEmptySlice", - "StructFieldHeadStringTagSlice", - "StructFieldPtrHeadSlice", - "StructFieldPtrHeadOmitEmptySlice", - "StructFieldPtrHeadStringTagSlice", - "StructFieldHeadStruct", - "StructFieldHeadOmitEmptyStruct", - "StructFieldHeadStringTagStruct", - "StructFieldPtrHeadStruct", - "StructFieldPtrHeadOmitEmptyStruct", - "StructFieldPtrHeadStringTagStruct", - "StructFieldHeadMarshalJSON", - "StructFieldHeadOmitEmptyMarshalJSON", - "StructFieldHeadStringTagMarshalJSON", - "StructFieldPtrHeadMarshalJSON", - "StructFieldPtrHeadOmitEmptyMarshalJSON", - "StructFieldPtrHeadStringTagMarshalJSON", - "StructFieldHeadMarshalText", - "StructFieldHeadOmitEmptyMarshalText", - "StructFieldHeadStringTagMarshalText", - "StructFieldPtrHeadMarshalText", - "StructFieldPtrHeadOmitEmptyMarshalText", - "StructFieldPtrHeadStringTagMarshalText", - "StructFieldHeadRecursive", - "StructFieldHeadOmitEmptyRecursive", - "StructFieldHeadStringTagRecursive", - "StructFieldPtrHeadRecursive", - "StructFieldPtrHeadOmitEmptyRecursive", - "StructFieldPtrHeadStringTagRecursive", - "StructFieldHeadIntString", - "StructFieldHeadOmitEmptyIntString", - "StructFieldHeadStringTagIntString", - "StructFieldPtrHeadIntString", - "StructFieldPtrHeadOmitEmptyIntString", - "StructFieldPtrHeadStringTagIntString", - "StructFieldHeadUintString", - "StructFieldHeadOmitEmptyUintString", - "StructFieldHeadStringTagUintString", - "StructFieldPtrHeadUintString", - "StructFieldPtrHeadOmitEmptyUintString", - "StructFieldPtrHeadStringTagUintString", - "StructFieldHeadIntPtr", - "StructFieldHeadOmitEmptyIntPtr", - "StructFieldHeadStringTagIntPtr", - "StructFieldPtrHeadIntPtr", - "StructFieldPtrHeadOmitEmptyIntPtr", - "StructFieldPtrHeadStringTagIntPtr", - "StructFieldHeadUintPtr", - "StructFieldHeadOmitEmptyUintPtr", - "StructFieldHeadStringTagUintPtr", - "StructFieldPtrHeadUintPtr", - "StructFieldPtrHeadOmitEmptyUintPtr", - "StructFieldPtrHeadStringTagUintPtr", - "StructFieldHeadFloat32Ptr", - "StructFieldHeadOmitEmptyFloat32Ptr", - "StructFieldHeadStringTagFloat32Ptr", - "StructFieldPtrHeadFloat32Ptr", - "StructFieldPtrHeadOmitEmptyFloat32Ptr", - "StructFieldPtrHeadStringTagFloat32Ptr", - "StructFieldHeadFloat64Ptr", - "StructFieldHeadOmitEmptyFloat64Ptr", - "StructFieldHeadStringTagFloat64Ptr", - "StructFieldPtrHeadFloat64Ptr", - "StructFieldPtrHeadOmitEmptyFloat64Ptr", - "StructFieldPtrHeadStringTagFloat64Ptr", - "StructFieldHeadBoolPtr", - "StructFieldHeadOmitEmptyBoolPtr", - "StructFieldHeadStringTagBoolPtr", - "StructFieldPtrHeadBoolPtr", - "StructFieldPtrHeadOmitEmptyBoolPtr", - "StructFieldPtrHeadStringTagBoolPtr", - "StructFieldHeadStringPtr", - "StructFieldHeadOmitEmptyStringPtr", - "StructFieldHeadStringTagStringPtr", - "StructFieldPtrHeadStringPtr", - "StructFieldPtrHeadOmitEmptyStringPtr", - "StructFieldPtrHeadStringTagStringPtr", - "StructFieldHeadBytesPtr", - "StructFieldHeadOmitEmptyBytesPtr", - "StructFieldHeadStringTagBytesPtr", - "StructFieldPtrHeadBytesPtr", - "StructFieldPtrHeadOmitEmptyBytesPtr", - "StructFieldPtrHeadStringTagBytesPtr", - "StructFieldHeadNumberPtr", - "StructFieldHeadOmitEmptyNumberPtr", - "StructFieldHeadStringTagNumberPtr", - "StructFieldPtrHeadNumberPtr", - "StructFieldPtrHeadOmitEmptyNumberPtr", - "StructFieldPtrHeadStringTagNumberPtr", - "StructFieldHeadArrayPtr", - "StructFieldHeadOmitEmptyArrayPtr", - "StructFieldHeadStringTagArrayPtr", - "StructFieldPtrHeadArrayPtr", - "StructFieldPtrHeadOmitEmptyArrayPtr", - "StructFieldPtrHeadStringTagArrayPtr", - "StructFieldHeadMapPtr", - "StructFieldHeadOmitEmptyMapPtr", - "StructFieldHeadStringTagMapPtr", - "StructFieldPtrHeadMapPtr", - "StructFieldPtrHeadOmitEmptyMapPtr", - "StructFieldPtrHeadStringTagMapPtr", - "StructFieldHeadSlicePtr", - "StructFieldHeadOmitEmptySlicePtr", - "StructFieldHeadStringTagSlicePtr", - "StructFieldPtrHeadSlicePtr", - "StructFieldPtrHeadOmitEmptySlicePtr", - "StructFieldPtrHeadStringTagSlicePtr", - "StructFieldHeadMarshalJSONPtr", - "StructFieldHeadOmitEmptyMarshalJSONPtr", - "StructFieldHeadStringTagMarshalJSONPtr", - "StructFieldPtrHeadMarshalJSONPtr", - "StructFieldPtrHeadOmitEmptyMarshalJSONPtr", - "StructFieldPtrHeadStringTagMarshalJSONPtr", - "StructFieldHeadMarshalTextPtr", - "StructFieldHeadOmitEmptyMarshalTextPtr", - "StructFieldHeadStringTagMarshalTextPtr", - "StructFieldPtrHeadMarshalTextPtr", - "StructFieldPtrHeadOmitEmptyMarshalTextPtr", - "StructFieldPtrHeadStringTagMarshalTextPtr", - "StructFieldHeadInterfacePtr", - "StructFieldHeadOmitEmptyInterfacePtr", - "StructFieldHeadStringTagInterfacePtr", - "StructFieldPtrHeadInterfacePtr", - "StructFieldPtrHeadOmitEmptyInterfacePtr", - "StructFieldPtrHeadStringTagInterfacePtr", - "StructFieldHeadRecursivePtr", - "StructFieldHeadOmitEmptyRecursivePtr", - "StructFieldHeadStringTagRecursivePtr", - "StructFieldPtrHeadRecursivePtr", - "StructFieldPtrHeadOmitEmptyRecursivePtr", - "StructFieldPtrHeadStringTagRecursivePtr", - "StructFieldHead", - "StructFieldHeadOmitEmpty", - "StructFieldHeadStringTag", - "StructFieldPtrHead", - "StructFieldPtrHeadOmitEmpty", - "StructFieldPtrHeadStringTag", - "StructFieldInt", - "StructFieldOmitEmptyInt", - "StructFieldStringTagInt", - "StructFieldUint", - "StructFieldOmitEmptyUint", - "StructFieldStringTagUint", - "StructFieldFloat32", - "StructFieldOmitEmptyFloat32", - "StructFieldStringTagFloat32", - "StructFieldFloat64", - "StructFieldOmitEmptyFloat64", - "StructFieldStringTagFloat64", - "StructFieldBool", - "StructFieldOmitEmptyBool", - "StructFieldStringTagBool", - "StructFieldString", - "StructFieldOmitEmptyString", - "StructFieldStringTagString", - "StructFieldBytes", - "StructFieldOmitEmptyBytes", - "StructFieldStringTagBytes", - "StructFieldNumber", - "StructFieldOmitEmptyNumber", - "StructFieldStringTagNumber", - "StructFieldArray", - "StructFieldOmitEmptyArray", - "StructFieldStringTagArray", - "StructFieldMap", - "StructFieldOmitEmptyMap", - "StructFieldStringTagMap", - "StructFieldSlice", - "StructFieldOmitEmptySlice", - "StructFieldStringTagSlice", - "StructFieldStruct", - "StructFieldOmitEmptyStruct", - "StructFieldStringTagStruct", - "StructFieldMarshalJSON", - "StructFieldOmitEmptyMarshalJSON", - "StructFieldStringTagMarshalJSON", - "StructFieldMarshalText", - "StructFieldOmitEmptyMarshalText", - "StructFieldStringTagMarshalText", - "StructFieldRecursive", - "StructFieldOmitEmptyRecursive", - "StructFieldStringTagRecursive", - "StructFieldIntString", - "StructFieldOmitEmptyIntString", - "StructFieldStringTagIntString", - "StructFieldUintString", - "StructFieldOmitEmptyUintString", - "StructFieldStringTagUintString", - "StructFieldIntPtr", - "StructFieldOmitEmptyIntPtr", - "StructFieldStringTagIntPtr", - "StructFieldUintPtr", - "StructFieldOmitEmptyUintPtr", - "StructFieldStringTagUintPtr", - "StructFieldFloat32Ptr", - "StructFieldOmitEmptyFloat32Ptr", - "StructFieldStringTagFloat32Ptr", - "StructFieldFloat64Ptr", - "StructFieldOmitEmptyFloat64Ptr", - "StructFieldStringTagFloat64Ptr", - "StructFieldBoolPtr", - "StructFieldOmitEmptyBoolPtr", - "StructFieldStringTagBoolPtr", - "StructFieldStringPtr", - "StructFieldOmitEmptyStringPtr", - "StructFieldStringTagStringPtr", - "StructFieldBytesPtr", - "StructFieldOmitEmptyBytesPtr", - "StructFieldStringTagBytesPtr", - "StructFieldNumberPtr", - "StructFieldOmitEmptyNumberPtr", - "StructFieldStringTagNumberPtr", - "StructFieldArrayPtr", - "StructFieldOmitEmptyArrayPtr", - "StructFieldStringTagArrayPtr", - "StructFieldMapPtr", - "StructFieldOmitEmptyMapPtr", - "StructFieldStringTagMapPtr", - "StructFieldSlicePtr", - "StructFieldOmitEmptySlicePtr", - "StructFieldStringTagSlicePtr", - "StructFieldMarshalJSONPtr", - "StructFieldOmitEmptyMarshalJSONPtr", - "StructFieldStringTagMarshalJSONPtr", - "StructFieldMarshalTextPtr", - "StructFieldOmitEmptyMarshalTextPtr", - "StructFieldStringTagMarshalTextPtr", - "StructFieldInterfacePtr", - "StructFieldOmitEmptyInterfacePtr", - "StructFieldStringTagInterfacePtr", - "StructFieldRecursivePtr", - "StructFieldOmitEmptyRecursivePtr", - "StructFieldStringTagRecursivePtr", - "StructField", - "StructFieldOmitEmpty", - "StructFieldStringTag", - "StructEndInt", - "StructEndOmitEmptyInt", - "StructEndStringTagInt", - "StructEndUint", - "StructEndOmitEmptyUint", - "StructEndStringTagUint", - "StructEndFloat32", - "StructEndOmitEmptyFloat32", - "StructEndStringTagFloat32", - "StructEndFloat64", - "StructEndOmitEmptyFloat64", - "StructEndStringTagFloat64", - "StructEndBool", - "StructEndOmitEmptyBool", - "StructEndStringTagBool", - "StructEndString", - "StructEndOmitEmptyString", - "StructEndStringTagString", - "StructEndBytes", - "StructEndOmitEmptyBytes", - "StructEndStringTagBytes", - "StructEndNumber", - "StructEndOmitEmptyNumber", - "StructEndStringTagNumber", - "StructEndArray", - "StructEndOmitEmptyArray", - "StructEndStringTagArray", - "StructEndMap", - "StructEndOmitEmptyMap", - "StructEndStringTagMap", - "StructEndSlice", - "StructEndOmitEmptySlice", - "StructEndStringTagSlice", - "StructEndStruct", - "StructEndOmitEmptyStruct", - "StructEndStringTagStruct", - "StructEndMarshalJSON", - "StructEndOmitEmptyMarshalJSON", - "StructEndStringTagMarshalJSON", - "StructEndMarshalText", - "StructEndOmitEmptyMarshalText", - "StructEndStringTagMarshalText", - "StructEndRecursive", - "StructEndOmitEmptyRecursive", - "StructEndStringTagRecursive", - "StructEndIntString", - "StructEndOmitEmptyIntString", - "StructEndStringTagIntString", - "StructEndUintString", - "StructEndOmitEmptyUintString", - "StructEndStringTagUintString", - "StructEndIntPtr", - "StructEndOmitEmptyIntPtr", - "StructEndStringTagIntPtr", - "StructEndUintPtr", - "StructEndOmitEmptyUintPtr", - "StructEndStringTagUintPtr", - "StructEndFloat32Ptr", - "StructEndOmitEmptyFloat32Ptr", - "StructEndStringTagFloat32Ptr", - "StructEndFloat64Ptr", - "StructEndOmitEmptyFloat64Ptr", - "StructEndStringTagFloat64Ptr", - "StructEndBoolPtr", - "StructEndOmitEmptyBoolPtr", - "StructEndStringTagBoolPtr", - "StructEndStringPtr", - "StructEndOmitEmptyStringPtr", - "StructEndStringTagStringPtr", - "StructEndBytesPtr", - "StructEndOmitEmptyBytesPtr", - "StructEndStringTagBytesPtr", - "StructEndNumberPtr", - "StructEndOmitEmptyNumberPtr", - "StructEndStringTagNumberPtr", - "StructEndArrayPtr", - "StructEndOmitEmptyArrayPtr", - "StructEndStringTagArrayPtr", - "StructEndMapPtr", - "StructEndOmitEmptyMapPtr", - "StructEndStringTagMapPtr", - "StructEndSlicePtr", - "StructEndOmitEmptySlicePtr", - "StructEndStringTagSlicePtr", - "StructEndMarshalJSONPtr", - "StructEndOmitEmptyMarshalJSONPtr", - "StructEndStringTagMarshalJSONPtr", - "StructEndMarshalTextPtr", - "StructEndOmitEmptyMarshalTextPtr", - "StructEndStringTagMarshalTextPtr", - "StructEndInterfacePtr", - "StructEndOmitEmptyInterfacePtr", - "StructEndStringTagInterfacePtr", - "StructEndRecursivePtr", - "StructEndOmitEmptyRecursivePtr", - "StructEndStringTagRecursivePtr", - "StructEnd", - "StructEndOmitEmpty", - "StructEndStringTag", -} - -type opType int - -const ( - opEnd opType = 0 - opInterface opType = 1 - opPtr opType = 2 - opSliceElem opType = 3 - opSliceEnd opType = 4 - opArrayElem opType = 5 - opArrayEnd opType = 6 - opMapKey opType = 7 - opMapValue opType = 8 - opMapEnd opType = 9 - opStructFieldRecursiveEnd opType = 10 - opStructAnonymousEnd opType = 11 - opInt opType = 12 - opUint opType = 13 - opFloat32 opType = 14 - opFloat64 opType = 15 - opBool opType = 16 - opString opType = 17 - opBytes opType = 18 - opNumber opType = 19 - opArray opType = 20 - opMap opType = 21 - opSlice opType = 22 - opStruct opType = 23 - opMarshalJSON opType = 24 - opMarshalText opType = 25 - opRecursive opType = 26 - opIntString opType = 27 - opUintString opType = 28 - opIntPtr opType = 29 - opUintPtr opType = 30 - opFloat32Ptr opType = 31 - opFloat64Ptr opType = 32 - opBoolPtr opType = 33 - opStringPtr opType = 34 - opBytesPtr opType = 35 - opNumberPtr opType = 36 - opArrayPtr opType = 37 - opMapPtr opType = 38 - opSlicePtr opType = 39 - opMarshalJSONPtr opType = 40 - opMarshalTextPtr opType = 41 - opInterfacePtr opType = 42 - opRecursivePtr opType = 43 - opStructFieldHeadInt opType = 44 - opStructFieldHeadOmitEmptyInt opType = 45 - opStructFieldHeadStringTagInt opType = 46 - opStructFieldPtrHeadInt opType = 47 - opStructFieldPtrHeadOmitEmptyInt opType = 48 - opStructFieldPtrHeadStringTagInt opType = 49 - opStructFieldHeadUint opType = 50 - opStructFieldHeadOmitEmptyUint opType = 51 - opStructFieldHeadStringTagUint opType = 52 - opStructFieldPtrHeadUint opType = 53 - opStructFieldPtrHeadOmitEmptyUint opType = 54 - opStructFieldPtrHeadStringTagUint opType = 55 - opStructFieldHeadFloat32 opType = 56 - opStructFieldHeadOmitEmptyFloat32 opType = 57 - opStructFieldHeadStringTagFloat32 opType = 58 - opStructFieldPtrHeadFloat32 opType = 59 - opStructFieldPtrHeadOmitEmptyFloat32 opType = 60 - opStructFieldPtrHeadStringTagFloat32 opType = 61 - opStructFieldHeadFloat64 opType = 62 - opStructFieldHeadOmitEmptyFloat64 opType = 63 - opStructFieldHeadStringTagFloat64 opType = 64 - opStructFieldPtrHeadFloat64 opType = 65 - opStructFieldPtrHeadOmitEmptyFloat64 opType = 66 - opStructFieldPtrHeadStringTagFloat64 opType = 67 - opStructFieldHeadBool opType = 68 - opStructFieldHeadOmitEmptyBool opType = 69 - opStructFieldHeadStringTagBool opType = 70 - opStructFieldPtrHeadBool opType = 71 - opStructFieldPtrHeadOmitEmptyBool opType = 72 - opStructFieldPtrHeadStringTagBool opType = 73 - opStructFieldHeadString opType = 74 - opStructFieldHeadOmitEmptyString opType = 75 - opStructFieldHeadStringTagString opType = 76 - opStructFieldPtrHeadString opType = 77 - opStructFieldPtrHeadOmitEmptyString opType = 78 - opStructFieldPtrHeadStringTagString opType = 79 - opStructFieldHeadBytes opType = 80 - opStructFieldHeadOmitEmptyBytes opType = 81 - opStructFieldHeadStringTagBytes opType = 82 - opStructFieldPtrHeadBytes opType = 83 - opStructFieldPtrHeadOmitEmptyBytes opType = 84 - opStructFieldPtrHeadStringTagBytes opType = 85 - opStructFieldHeadNumber opType = 86 - opStructFieldHeadOmitEmptyNumber opType = 87 - opStructFieldHeadStringTagNumber opType = 88 - opStructFieldPtrHeadNumber opType = 89 - opStructFieldPtrHeadOmitEmptyNumber opType = 90 - opStructFieldPtrHeadStringTagNumber opType = 91 - opStructFieldHeadArray opType = 92 - opStructFieldHeadOmitEmptyArray opType = 93 - opStructFieldHeadStringTagArray opType = 94 - opStructFieldPtrHeadArray opType = 95 - opStructFieldPtrHeadOmitEmptyArray opType = 96 - opStructFieldPtrHeadStringTagArray opType = 97 - opStructFieldHeadMap opType = 98 - opStructFieldHeadOmitEmptyMap opType = 99 - opStructFieldHeadStringTagMap opType = 100 - opStructFieldPtrHeadMap opType = 101 - opStructFieldPtrHeadOmitEmptyMap opType = 102 - opStructFieldPtrHeadStringTagMap opType = 103 - opStructFieldHeadSlice opType = 104 - opStructFieldHeadOmitEmptySlice opType = 105 - opStructFieldHeadStringTagSlice opType = 106 - opStructFieldPtrHeadSlice opType = 107 - opStructFieldPtrHeadOmitEmptySlice opType = 108 - opStructFieldPtrHeadStringTagSlice opType = 109 - opStructFieldHeadStruct opType = 110 - opStructFieldHeadOmitEmptyStruct opType = 111 - opStructFieldHeadStringTagStruct opType = 112 - opStructFieldPtrHeadStruct opType = 113 - opStructFieldPtrHeadOmitEmptyStruct opType = 114 - opStructFieldPtrHeadStringTagStruct opType = 115 - opStructFieldHeadMarshalJSON opType = 116 - opStructFieldHeadOmitEmptyMarshalJSON opType = 117 - opStructFieldHeadStringTagMarshalJSON opType = 118 - opStructFieldPtrHeadMarshalJSON opType = 119 - opStructFieldPtrHeadOmitEmptyMarshalJSON opType = 120 - opStructFieldPtrHeadStringTagMarshalJSON opType = 121 - opStructFieldHeadMarshalText opType = 122 - opStructFieldHeadOmitEmptyMarshalText opType = 123 - opStructFieldHeadStringTagMarshalText opType = 124 - opStructFieldPtrHeadMarshalText opType = 125 - opStructFieldPtrHeadOmitEmptyMarshalText opType = 126 - opStructFieldPtrHeadStringTagMarshalText opType = 127 - opStructFieldHeadRecursive opType = 128 - opStructFieldHeadOmitEmptyRecursive opType = 129 - opStructFieldHeadStringTagRecursive opType = 130 - opStructFieldPtrHeadRecursive opType = 131 - opStructFieldPtrHeadOmitEmptyRecursive opType = 132 - opStructFieldPtrHeadStringTagRecursive opType = 133 - opStructFieldHeadIntString opType = 134 - opStructFieldHeadOmitEmptyIntString opType = 135 - opStructFieldHeadStringTagIntString opType = 136 - opStructFieldPtrHeadIntString opType = 137 - opStructFieldPtrHeadOmitEmptyIntString opType = 138 - opStructFieldPtrHeadStringTagIntString opType = 139 - opStructFieldHeadUintString opType = 140 - opStructFieldHeadOmitEmptyUintString opType = 141 - opStructFieldHeadStringTagUintString opType = 142 - opStructFieldPtrHeadUintString opType = 143 - opStructFieldPtrHeadOmitEmptyUintString opType = 144 - opStructFieldPtrHeadStringTagUintString opType = 145 - opStructFieldHeadIntPtr opType = 146 - opStructFieldHeadOmitEmptyIntPtr opType = 147 - opStructFieldHeadStringTagIntPtr opType = 148 - opStructFieldPtrHeadIntPtr opType = 149 - opStructFieldPtrHeadOmitEmptyIntPtr opType = 150 - opStructFieldPtrHeadStringTagIntPtr opType = 151 - opStructFieldHeadUintPtr opType = 152 - opStructFieldHeadOmitEmptyUintPtr opType = 153 - opStructFieldHeadStringTagUintPtr opType = 154 - opStructFieldPtrHeadUintPtr opType = 155 - opStructFieldPtrHeadOmitEmptyUintPtr opType = 156 - opStructFieldPtrHeadStringTagUintPtr opType = 157 - opStructFieldHeadFloat32Ptr opType = 158 - opStructFieldHeadOmitEmptyFloat32Ptr opType = 159 - opStructFieldHeadStringTagFloat32Ptr opType = 160 - opStructFieldPtrHeadFloat32Ptr opType = 161 - opStructFieldPtrHeadOmitEmptyFloat32Ptr opType = 162 - opStructFieldPtrHeadStringTagFloat32Ptr opType = 163 - opStructFieldHeadFloat64Ptr opType = 164 - opStructFieldHeadOmitEmptyFloat64Ptr opType = 165 - opStructFieldHeadStringTagFloat64Ptr opType = 166 - opStructFieldPtrHeadFloat64Ptr opType = 167 - opStructFieldPtrHeadOmitEmptyFloat64Ptr opType = 168 - opStructFieldPtrHeadStringTagFloat64Ptr opType = 169 - opStructFieldHeadBoolPtr opType = 170 - opStructFieldHeadOmitEmptyBoolPtr opType = 171 - opStructFieldHeadStringTagBoolPtr opType = 172 - opStructFieldPtrHeadBoolPtr opType = 173 - opStructFieldPtrHeadOmitEmptyBoolPtr opType = 174 - opStructFieldPtrHeadStringTagBoolPtr opType = 175 - opStructFieldHeadStringPtr opType = 176 - opStructFieldHeadOmitEmptyStringPtr opType = 177 - opStructFieldHeadStringTagStringPtr opType = 178 - opStructFieldPtrHeadStringPtr opType = 179 - opStructFieldPtrHeadOmitEmptyStringPtr opType = 180 - opStructFieldPtrHeadStringTagStringPtr opType = 181 - opStructFieldHeadBytesPtr opType = 182 - opStructFieldHeadOmitEmptyBytesPtr opType = 183 - opStructFieldHeadStringTagBytesPtr opType = 184 - opStructFieldPtrHeadBytesPtr opType = 185 - opStructFieldPtrHeadOmitEmptyBytesPtr opType = 186 - opStructFieldPtrHeadStringTagBytesPtr opType = 187 - opStructFieldHeadNumberPtr opType = 188 - opStructFieldHeadOmitEmptyNumberPtr opType = 189 - opStructFieldHeadStringTagNumberPtr opType = 190 - opStructFieldPtrHeadNumberPtr opType = 191 - opStructFieldPtrHeadOmitEmptyNumberPtr opType = 192 - opStructFieldPtrHeadStringTagNumberPtr opType = 193 - opStructFieldHeadArrayPtr opType = 194 - opStructFieldHeadOmitEmptyArrayPtr opType = 195 - opStructFieldHeadStringTagArrayPtr opType = 196 - opStructFieldPtrHeadArrayPtr opType = 197 - opStructFieldPtrHeadOmitEmptyArrayPtr opType = 198 - opStructFieldPtrHeadStringTagArrayPtr opType = 199 - opStructFieldHeadMapPtr opType = 200 - opStructFieldHeadOmitEmptyMapPtr opType = 201 - opStructFieldHeadStringTagMapPtr opType = 202 - opStructFieldPtrHeadMapPtr opType = 203 - opStructFieldPtrHeadOmitEmptyMapPtr opType = 204 - opStructFieldPtrHeadStringTagMapPtr opType = 205 - opStructFieldHeadSlicePtr opType = 206 - opStructFieldHeadOmitEmptySlicePtr opType = 207 - opStructFieldHeadStringTagSlicePtr opType = 208 - opStructFieldPtrHeadSlicePtr opType = 209 - opStructFieldPtrHeadOmitEmptySlicePtr opType = 210 - opStructFieldPtrHeadStringTagSlicePtr opType = 211 - opStructFieldHeadMarshalJSONPtr opType = 212 - opStructFieldHeadOmitEmptyMarshalJSONPtr opType = 213 - opStructFieldHeadStringTagMarshalJSONPtr opType = 214 - opStructFieldPtrHeadMarshalJSONPtr opType = 215 - opStructFieldPtrHeadOmitEmptyMarshalJSONPtr opType = 216 - opStructFieldPtrHeadStringTagMarshalJSONPtr opType = 217 - opStructFieldHeadMarshalTextPtr opType = 218 - opStructFieldHeadOmitEmptyMarshalTextPtr opType = 219 - opStructFieldHeadStringTagMarshalTextPtr opType = 220 - opStructFieldPtrHeadMarshalTextPtr opType = 221 - opStructFieldPtrHeadOmitEmptyMarshalTextPtr opType = 222 - opStructFieldPtrHeadStringTagMarshalTextPtr opType = 223 - opStructFieldHeadInterfacePtr opType = 224 - opStructFieldHeadOmitEmptyInterfacePtr opType = 225 - opStructFieldHeadStringTagInterfacePtr opType = 226 - opStructFieldPtrHeadInterfacePtr opType = 227 - opStructFieldPtrHeadOmitEmptyInterfacePtr opType = 228 - opStructFieldPtrHeadStringTagInterfacePtr opType = 229 - opStructFieldHeadRecursivePtr opType = 230 - opStructFieldHeadOmitEmptyRecursivePtr opType = 231 - opStructFieldHeadStringTagRecursivePtr opType = 232 - opStructFieldPtrHeadRecursivePtr opType = 233 - opStructFieldPtrHeadOmitEmptyRecursivePtr opType = 234 - opStructFieldPtrHeadStringTagRecursivePtr opType = 235 - opStructFieldHead opType = 236 - opStructFieldHeadOmitEmpty opType = 237 - opStructFieldHeadStringTag opType = 238 - opStructFieldPtrHead opType = 239 - opStructFieldPtrHeadOmitEmpty opType = 240 - opStructFieldPtrHeadStringTag opType = 241 - opStructFieldInt opType = 242 - opStructFieldOmitEmptyInt opType = 243 - opStructFieldStringTagInt opType = 244 - opStructFieldUint opType = 245 - opStructFieldOmitEmptyUint opType = 246 - opStructFieldStringTagUint opType = 247 - opStructFieldFloat32 opType = 248 - opStructFieldOmitEmptyFloat32 opType = 249 - opStructFieldStringTagFloat32 opType = 250 - opStructFieldFloat64 opType = 251 - opStructFieldOmitEmptyFloat64 opType = 252 - opStructFieldStringTagFloat64 opType = 253 - opStructFieldBool opType = 254 - opStructFieldOmitEmptyBool opType = 255 - opStructFieldStringTagBool opType = 256 - opStructFieldString opType = 257 - opStructFieldOmitEmptyString opType = 258 - opStructFieldStringTagString opType = 259 - opStructFieldBytes opType = 260 - opStructFieldOmitEmptyBytes opType = 261 - opStructFieldStringTagBytes opType = 262 - opStructFieldNumber opType = 263 - opStructFieldOmitEmptyNumber opType = 264 - opStructFieldStringTagNumber opType = 265 - opStructFieldArray opType = 266 - opStructFieldOmitEmptyArray opType = 267 - opStructFieldStringTagArray opType = 268 - opStructFieldMap opType = 269 - opStructFieldOmitEmptyMap opType = 270 - opStructFieldStringTagMap opType = 271 - opStructFieldSlice opType = 272 - opStructFieldOmitEmptySlice opType = 273 - opStructFieldStringTagSlice opType = 274 - opStructFieldStruct opType = 275 - opStructFieldOmitEmptyStruct opType = 276 - opStructFieldStringTagStruct opType = 277 - opStructFieldMarshalJSON opType = 278 - opStructFieldOmitEmptyMarshalJSON opType = 279 - opStructFieldStringTagMarshalJSON opType = 280 - opStructFieldMarshalText opType = 281 - opStructFieldOmitEmptyMarshalText opType = 282 - opStructFieldStringTagMarshalText opType = 283 - opStructFieldRecursive opType = 284 - opStructFieldOmitEmptyRecursive opType = 285 - opStructFieldStringTagRecursive opType = 286 - opStructFieldIntString opType = 287 - opStructFieldOmitEmptyIntString opType = 288 - opStructFieldStringTagIntString opType = 289 - opStructFieldUintString opType = 290 - opStructFieldOmitEmptyUintString opType = 291 - opStructFieldStringTagUintString opType = 292 - opStructFieldIntPtr opType = 293 - opStructFieldOmitEmptyIntPtr opType = 294 - opStructFieldStringTagIntPtr opType = 295 - opStructFieldUintPtr opType = 296 - opStructFieldOmitEmptyUintPtr opType = 297 - opStructFieldStringTagUintPtr opType = 298 - opStructFieldFloat32Ptr opType = 299 - opStructFieldOmitEmptyFloat32Ptr opType = 300 - opStructFieldStringTagFloat32Ptr opType = 301 - opStructFieldFloat64Ptr opType = 302 - opStructFieldOmitEmptyFloat64Ptr opType = 303 - opStructFieldStringTagFloat64Ptr opType = 304 - opStructFieldBoolPtr opType = 305 - opStructFieldOmitEmptyBoolPtr opType = 306 - opStructFieldStringTagBoolPtr opType = 307 - opStructFieldStringPtr opType = 308 - opStructFieldOmitEmptyStringPtr opType = 309 - opStructFieldStringTagStringPtr opType = 310 - opStructFieldBytesPtr opType = 311 - opStructFieldOmitEmptyBytesPtr opType = 312 - opStructFieldStringTagBytesPtr opType = 313 - opStructFieldNumberPtr opType = 314 - opStructFieldOmitEmptyNumberPtr opType = 315 - opStructFieldStringTagNumberPtr opType = 316 - opStructFieldArrayPtr opType = 317 - opStructFieldOmitEmptyArrayPtr opType = 318 - opStructFieldStringTagArrayPtr opType = 319 - opStructFieldMapPtr opType = 320 - opStructFieldOmitEmptyMapPtr opType = 321 - opStructFieldStringTagMapPtr opType = 322 - opStructFieldSlicePtr opType = 323 - opStructFieldOmitEmptySlicePtr opType = 324 - opStructFieldStringTagSlicePtr opType = 325 - opStructFieldMarshalJSONPtr opType = 326 - opStructFieldOmitEmptyMarshalJSONPtr opType = 327 - opStructFieldStringTagMarshalJSONPtr opType = 328 - opStructFieldMarshalTextPtr opType = 329 - opStructFieldOmitEmptyMarshalTextPtr opType = 330 - opStructFieldStringTagMarshalTextPtr opType = 331 - opStructFieldInterfacePtr opType = 332 - opStructFieldOmitEmptyInterfacePtr opType = 333 - opStructFieldStringTagInterfacePtr opType = 334 - opStructFieldRecursivePtr opType = 335 - opStructFieldOmitEmptyRecursivePtr opType = 336 - opStructFieldStringTagRecursivePtr opType = 337 - opStructField opType = 338 - opStructFieldOmitEmpty opType = 339 - opStructFieldStringTag opType = 340 - opStructEndInt opType = 341 - opStructEndOmitEmptyInt opType = 342 - opStructEndStringTagInt opType = 343 - opStructEndUint opType = 344 - opStructEndOmitEmptyUint opType = 345 - opStructEndStringTagUint opType = 346 - opStructEndFloat32 opType = 347 - opStructEndOmitEmptyFloat32 opType = 348 - opStructEndStringTagFloat32 opType = 349 - opStructEndFloat64 opType = 350 - opStructEndOmitEmptyFloat64 opType = 351 - opStructEndStringTagFloat64 opType = 352 - opStructEndBool opType = 353 - opStructEndOmitEmptyBool opType = 354 - opStructEndStringTagBool opType = 355 - opStructEndString opType = 356 - opStructEndOmitEmptyString opType = 357 - opStructEndStringTagString opType = 358 - opStructEndBytes opType = 359 - opStructEndOmitEmptyBytes opType = 360 - opStructEndStringTagBytes opType = 361 - opStructEndNumber opType = 362 - opStructEndOmitEmptyNumber opType = 363 - opStructEndStringTagNumber opType = 364 - opStructEndArray opType = 365 - opStructEndOmitEmptyArray opType = 366 - opStructEndStringTagArray opType = 367 - opStructEndMap opType = 368 - opStructEndOmitEmptyMap opType = 369 - opStructEndStringTagMap opType = 370 - opStructEndSlice opType = 371 - opStructEndOmitEmptySlice opType = 372 - opStructEndStringTagSlice opType = 373 - opStructEndStruct opType = 374 - opStructEndOmitEmptyStruct opType = 375 - opStructEndStringTagStruct opType = 376 - opStructEndMarshalJSON opType = 377 - opStructEndOmitEmptyMarshalJSON opType = 378 - opStructEndStringTagMarshalJSON opType = 379 - opStructEndMarshalText opType = 380 - opStructEndOmitEmptyMarshalText opType = 381 - opStructEndStringTagMarshalText opType = 382 - opStructEndRecursive opType = 383 - opStructEndOmitEmptyRecursive opType = 384 - opStructEndStringTagRecursive opType = 385 - opStructEndIntString opType = 386 - opStructEndOmitEmptyIntString opType = 387 - opStructEndStringTagIntString opType = 388 - opStructEndUintString opType = 389 - opStructEndOmitEmptyUintString opType = 390 - opStructEndStringTagUintString opType = 391 - opStructEndIntPtr opType = 392 - opStructEndOmitEmptyIntPtr opType = 393 - opStructEndStringTagIntPtr opType = 394 - opStructEndUintPtr opType = 395 - opStructEndOmitEmptyUintPtr opType = 396 - opStructEndStringTagUintPtr opType = 397 - opStructEndFloat32Ptr opType = 398 - opStructEndOmitEmptyFloat32Ptr opType = 399 - opStructEndStringTagFloat32Ptr opType = 400 - opStructEndFloat64Ptr opType = 401 - opStructEndOmitEmptyFloat64Ptr opType = 402 - opStructEndStringTagFloat64Ptr opType = 403 - opStructEndBoolPtr opType = 404 - opStructEndOmitEmptyBoolPtr opType = 405 - opStructEndStringTagBoolPtr opType = 406 - opStructEndStringPtr opType = 407 - opStructEndOmitEmptyStringPtr opType = 408 - opStructEndStringTagStringPtr opType = 409 - opStructEndBytesPtr opType = 410 - opStructEndOmitEmptyBytesPtr opType = 411 - opStructEndStringTagBytesPtr opType = 412 - opStructEndNumberPtr opType = 413 - opStructEndOmitEmptyNumberPtr opType = 414 - opStructEndStringTagNumberPtr opType = 415 - opStructEndArrayPtr opType = 416 - opStructEndOmitEmptyArrayPtr opType = 417 - opStructEndStringTagArrayPtr opType = 418 - opStructEndMapPtr opType = 419 - opStructEndOmitEmptyMapPtr opType = 420 - opStructEndStringTagMapPtr opType = 421 - opStructEndSlicePtr opType = 422 - opStructEndOmitEmptySlicePtr opType = 423 - opStructEndStringTagSlicePtr opType = 424 - opStructEndMarshalJSONPtr opType = 425 - opStructEndOmitEmptyMarshalJSONPtr opType = 426 - opStructEndStringTagMarshalJSONPtr opType = 427 - opStructEndMarshalTextPtr opType = 428 - opStructEndOmitEmptyMarshalTextPtr opType = 429 - opStructEndStringTagMarshalTextPtr opType = 430 - opStructEndInterfacePtr opType = 431 - opStructEndOmitEmptyInterfacePtr opType = 432 - opStructEndStringTagInterfacePtr opType = 433 - opStructEndRecursivePtr opType = 434 - opStructEndOmitEmptyRecursivePtr opType = 435 - opStructEndStringTagRecursivePtr opType = 436 - opStructEnd opType = 437 - opStructEndOmitEmpty opType = 438 - opStructEndStringTag opType = 439 -) - -func (t opType) String() string { - if int(t) >= 440 { - return "" - } - return opTypeStrings[int(t)] -} - -func (t opType) codeType() codeType { - if strings.Contains(t.String(), "Struct") { - if strings.Contains(t.String(), "End") { - return codeStructEnd - } - return codeStructField - } - if t.String() == "Array" || t.String() == "ArrayPtr" { - return codeArrayHead - } - if strings.Contains(t.String(), "ArrayElem") { - return codeArrayElem - } - if t.String() == "Slice" || t.String() == "SlicePtr" { - return codeSliceHead - } - if strings.Contains(t.String(), "SliceElem") { - return codeSliceElem - } - if t.String() == "Map" || t.String() == "MapPtr" { - return codeMapHead - } - if strings.Contains(t.String(), "MapKey") { - return codeMapKey - } - if strings.Contains(t.String(), "MapValue") { - return codeMapValue - } - if strings.Contains(t.String(), "MapEnd") { - return codeMapEnd - } - - return codeOp -} - -func (t opType) headToPtrHead() opType { - if strings.Index(t.String(), "PtrHead") > 0 { - return t - } - - idx := strings.Index(t.String(), "Field") - if idx == -1 { - return t - } - suffix := "Ptr" + t.String()[idx+len("Field"):] - - const toPtrOffset = 3 - if strings.Contains(opType(int(t)+toPtrOffset).String(), suffix) { - return opType(int(t) + toPtrOffset) - } - return t -} - -func (t opType) headToOmitEmptyHead() opType { - const toOmitEmptyOffset = 1 - if strings.Contains(opType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { - return opType(int(t) + toOmitEmptyOffset) - } - - return t -} - -func (t opType) headToStringTagHead() opType { - const toStringTagOffset = 2 - if strings.Contains(opType(int(t)+toStringTagOffset).String(), "StringTag") { - return opType(int(t) + toStringTagOffset) - } - return t -} - -func (t opType) ptrHeadToHead() opType { - idx := strings.Index(t.String(), "Ptr") - if idx == -1 { - return t - } - suffix := t.String()[idx+len("Ptr"):] - - const toPtrOffset = 3 - if strings.Contains(opType(int(t)-toPtrOffset).String(), suffix) { - return opType(int(t) - toPtrOffset) - } - return t -} - -func (t opType) fieldToEnd() opType { - switch t { - case opStructFieldInt: - return opStructEndInt - case opStructFieldOmitEmptyInt: - return opStructEndOmitEmptyInt - case opStructFieldStringTagInt: - return opStructEndStringTagInt - case opStructFieldUint: - return opStructEndUint - case opStructFieldOmitEmptyUint: - return opStructEndOmitEmptyUint - case opStructFieldStringTagUint: - return opStructEndStringTagUint - case opStructFieldFloat32: - return opStructEndFloat32 - case opStructFieldOmitEmptyFloat32: - return opStructEndOmitEmptyFloat32 - case opStructFieldStringTagFloat32: - return opStructEndStringTagFloat32 - case opStructFieldFloat64: - return opStructEndFloat64 - case opStructFieldOmitEmptyFloat64: - return opStructEndOmitEmptyFloat64 - case opStructFieldStringTagFloat64: - return opStructEndStringTagFloat64 - case opStructFieldBool: - return opStructEndBool - case opStructFieldOmitEmptyBool: - return opStructEndOmitEmptyBool - case opStructFieldStringTagBool: - return opStructEndStringTagBool - case opStructFieldString: - return opStructEndString - case opStructFieldOmitEmptyString: - return opStructEndOmitEmptyString - case opStructFieldStringTagString: - return opStructEndStringTagString - case opStructFieldBytes: - return opStructEndBytes - case opStructFieldOmitEmptyBytes: - return opStructEndOmitEmptyBytes - case opStructFieldStringTagBytes: - return opStructEndStringTagBytes - case opStructFieldNumber: - return opStructEndNumber - case opStructFieldOmitEmptyNumber: - return opStructEndOmitEmptyNumber - case opStructFieldStringTagNumber: - return opStructEndStringTagNumber - case opStructFieldMarshalJSON: - return opStructEndMarshalJSON - case opStructFieldOmitEmptyMarshalJSON: - return opStructEndOmitEmptyMarshalJSON - case opStructFieldStringTagMarshalJSON: - return opStructEndStringTagMarshalJSON - case opStructFieldMarshalText: - return opStructEndMarshalText - case opStructFieldOmitEmptyMarshalText: - return opStructEndOmitEmptyMarshalText - case opStructFieldStringTagMarshalText: - return opStructEndStringTagMarshalText - case opStructFieldIntString: - return opStructEndIntString - case opStructFieldOmitEmptyIntString: - return opStructEndOmitEmptyIntString - case opStructFieldStringTagIntString: - return opStructEndStringTagIntString - case opStructFieldUintString: - return opStructEndUintString - case opStructFieldOmitEmptyUintString: - return opStructEndOmitEmptyUintString - case opStructFieldStringTagUintString: - return opStructEndStringTagUintString - case opStructFieldIntPtr: - return opStructEndIntPtr - case opStructFieldOmitEmptyIntPtr: - return opStructEndOmitEmptyIntPtr - case opStructFieldStringTagIntPtr: - return opStructEndStringTagIntPtr - case opStructFieldUintPtr: - return opStructEndUintPtr - case opStructFieldOmitEmptyUintPtr: - return opStructEndOmitEmptyUintPtr - case opStructFieldStringTagUintPtr: - return opStructEndStringTagUintPtr - case opStructFieldFloat32Ptr: - return opStructEndFloat32Ptr - case opStructFieldOmitEmptyFloat32Ptr: - return opStructEndOmitEmptyFloat32Ptr - case opStructFieldStringTagFloat32Ptr: - return opStructEndStringTagFloat32Ptr - case opStructFieldFloat64Ptr: - return opStructEndFloat64Ptr - case opStructFieldOmitEmptyFloat64Ptr: - return opStructEndOmitEmptyFloat64Ptr - case opStructFieldStringTagFloat64Ptr: - return opStructEndStringTagFloat64Ptr - case opStructFieldBoolPtr: - return opStructEndBoolPtr - case opStructFieldOmitEmptyBoolPtr: - return opStructEndOmitEmptyBoolPtr - case opStructFieldStringTagBoolPtr: - return opStructEndStringTagBoolPtr - case opStructFieldStringPtr: - return opStructEndStringPtr - case opStructFieldOmitEmptyStringPtr: - return opStructEndOmitEmptyStringPtr - case opStructFieldStringTagStringPtr: - return opStructEndStringTagStringPtr - case opStructFieldBytesPtr: - return opStructEndBytesPtr - case opStructFieldOmitEmptyBytesPtr: - return opStructEndOmitEmptyBytesPtr - case opStructFieldStringTagBytesPtr: - return opStructEndStringTagBytesPtr - case opStructFieldNumberPtr: - return opStructEndNumberPtr - case opStructFieldOmitEmptyNumberPtr: - return opStructEndOmitEmptyNumberPtr - case opStructFieldStringTagNumberPtr: - return opStructEndStringTagNumberPtr - case opStructFieldArrayPtr: - return opStructEndArrayPtr - case opStructFieldOmitEmptyArrayPtr: - return opStructEndOmitEmptyArrayPtr - case opStructFieldStringTagArrayPtr: - return opStructEndStringTagArrayPtr - case opStructFieldMapPtr: - return opStructEndMapPtr - case opStructFieldOmitEmptyMapPtr: - return opStructEndOmitEmptyMapPtr - case opStructFieldStringTagMapPtr: - return opStructEndStringTagMapPtr - case opStructFieldSlicePtr: - return opStructEndSlicePtr - case opStructFieldOmitEmptySlicePtr: - return opStructEndOmitEmptySlicePtr - case opStructFieldStringTagSlicePtr: - return opStructEndStringTagSlicePtr - case opStructFieldMarshalJSONPtr: - return opStructEndMarshalJSONPtr - case opStructFieldOmitEmptyMarshalJSONPtr: - return opStructEndOmitEmptyMarshalJSONPtr - case opStructFieldStringTagMarshalJSONPtr: - return opStructEndStringTagMarshalJSONPtr - case opStructFieldMarshalTextPtr: - return opStructEndMarshalTextPtr - case opStructFieldOmitEmptyMarshalTextPtr: - return opStructEndOmitEmptyMarshalTextPtr - case opStructFieldStringTagMarshalTextPtr: - return opStructEndStringTagMarshalTextPtr - case opStructFieldInterfacePtr: - return opStructEndInterfacePtr - case opStructFieldOmitEmptyInterfacePtr: - return opStructEndOmitEmptyInterfacePtr - case opStructFieldStringTagInterfacePtr: - return opStructEndStringTagInterfacePtr - case opStructFieldRecursivePtr: - return opStructEndRecursivePtr - case opStructFieldOmitEmptyRecursivePtr: - return opStructEndOmitEmptyRecursivePtr - case opStructFieldStringTagRecursivePtr: - return opStructEndStringTagRecursivePtr - } - return t -} - -func (t opType) fieldToOmitEmptyField() opType { - const toOmitEmptyOffset = 1 - if strings.Contains(opType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { - return opType(int(t) + toOmitEmptyOffset) - } - return t -} - -func (t opType) fieldToStringTagField() opType { - const toStringTagOffset = 2 - if strings.Contains(opType(int(t)+toStringTagOffset).String(), "StringTag") { - return opType(int(t) + toStringTagOffset) - } - return t -} diff --git a/encode_string.go b/encode_string.go deleted file mode 100644 index 7797101..0000000 --- a/encode_string.go +++ /dev/null @@ -1,637 +0,0 @@ -package json - -import ( - "math/bits" - "reflect" - "unicode/utf8" - "unsafe" -) - -const ( - lsb = 0x0101010101010101 - msb = 0x8080808080808080 -) - -var needEscapeWithHTML = [256]bool{ - '"': true, - '&': true, - '<': true, - '>': true, - '\\': true, - 0x00: true, - 0x01: true, - 0x02: true, - 0x03: true, - 0x04: true, - 0x05: true, - 0x06: true, - 0x07: true, - 0x08: true, - 0x09: true, - 0x0a: true, - 0x0b: true, - 0x0c: true, - 0x0d: true, - 0x0e: true, - 0x0f: true, - 0x10: true, - 0x11: true, - 0x12: true, - 0x13: true, - 0x14: true, - 0x15: true, - 0x16: true, - 0x17: true, - 0x18: true, - 0x19: true, - 0x1a: true, - 0x1b: true, - 0x1c: true, - 0x1d: true, - 0x1e: true, - 0x1f: true, - /* 0x20 - 0x7f */ - 0x80: true, - 0x81: true, - 0x82: true, - 0x83: true, - 0x84: true, - 0x85: true, - 0x86: true, - 0x87: true, - 0x88: true, - 0x89: true, - 0x8a: true, - 0x8b: true, - 0x8c: true, - 0x8d: true, - 0x8e: true, - 0x8f: true, - 0x90: true, - 0x91: true, - 0x92: true, - 0x93: true, - 0x94: true, - 0x95: true, - 0x96: true, - 0x97: true, - 0x98: true, - 0x99: true, - 0x9a: true, - 0x9b: true, - 0x9c: true, - 0x9d: true, - 0x9e: true, - 0x9f: true, - 0xa0: true, - 0xa1: true, - 0xa2: true, - 0xa3: true, - 0xa4: true, - 0xa5: true, - 0xa6: true, - 0xa7: true, - 0xa8: true, - 0xa9: true, - 0xaa: true, - 0xab: true, - 0xac: true, - 0xad: true, - 0xae: true, - 0xaf: true, - 0xb0: true, - 0xb1: true, - 0xb2: true, - 0xb3: true, - 0xb4: true, - 0xb5: true, - 0xb6: true, - 0xb7: true, - 0xb8: true, - 0xb9: true, - 0xba: true, - 0xbb: true, - 0xbc: true, - 0xbd: true, - 0xbe: true, - 0xbf: true, - 0xc0: true, - 0xc1: true, - 0xc2: true, - 0xc3: true, - 0xc4: true, - 0xc5: true, - 0xc6: true, - 0xc7: true, - 0xc8: true, - 0xc9: true, - 0xca: true, - 0xcb: true, - 0xcc: true, - 0xcd: true, - 0xce: true, - 0xcf: true, - 0xd0: true, - 0xd1: true, - 0xd2: true, - 0xd3: true, - 0xd4: true, - 0xd5: true, - 0xd6: true, - 0xd7: true, - 0xd8: true, - 0xd9: true, - 0xda: true, - 0xdb: true, - 0xdc: true, - 0xdd: true, - 0xde: true, - 0xdf: true, - 0xe0: true, - 0xe1: true, - 0xe2: true, - 0xe3: true, - 0xe4: true, - 0xe5: true, - 0xe6: true, - 0xe7: true, - 0xe8: true, - 0xe9: true, - 0xea: true, - 0xeb: true, - 0xec: true, - 0xed: true, - 0xee: true, - 0xef: true, - 0xf0: true, - 0xf1: true, - 0xf2: true, - 0xf3: true, - 0xf4: true, - 0xf5: true, - 0xf6: true, - 0xf7: true, - 0xf8: true, - 0xf9: true, - 0xfa: true, - 0xfb: true, - 0xfc: true, - 0xfd: true, - 0xfe: true, - 0xff: true, -} - -var needEscape = [256]bool{ - '"': true, - '\\': true, - 0x00: true, - 0x01: true, - 0x02: true, - 0x03: true, - 0x04: true, - 0x05: true, - 0x06: true, - 0x07: true, - 0x08: true, - 0x09: true, - 0x0a: true, - 0x0b: true, - 0x0c: true, - 0x0d: true, - 0x0e: true, - 0x0f: true, - 0x10: true, - 0x11: true, - 0x12: true, - 0x13: true, - 0x14: true, - 0x15: true, - 0x16: true, - 0x17: true, - 0x18: true, - 0x19: true, - 0x1a: true, - 0x1b: true, - 0x1c: true, - 0x1d: true, - 0x1e: true, - 0x1f: true, - /* 0x20 - 0x7f */ - 0x80: true, - 0x81: true, - 0x82: true, - 0x83: true, - 0x84: true, - 0x85: true, - 0x86: true, - 0x87: true, - 0x88: true, - 0x89: true, - 0x8a: true, - 0x8b: true, - 0x8c: true, - 0x8d: true, - 0x8e: true, - 0x8f: true, - 0x90: true, - 0x91: true, - 0x92: true, - 0x93: true, - 0x94: true, - 0x95: true, - 0x96: true, - 0x97: true, - 0x98: true, - 0x99: true, - 0x9a: true, - 0x9b: true, - 0x9c: true, - 0x9d: true, - 0x9e: true, - 0x9f: true, - 0xa0: true, - 0xa1: true, - 0xa2: true, - 0xa3: true, - 0xa4: true, - 0xa5: true, - 0xa6: true, - 0xa7: true, - 0xa8: true, - 0xa9: true, - 0xaa: true, - 0xab: true, - 0xac: true, - 0xad: true, - 0xae: true, - 0xaf: true, - 0xb0: true, - 0xb1: true, - 0xb2: true, - 0xb3: true, - 0xb4: true, - 0xb5: true, - 0xb6: true, - 0xb7: true, - 0xb8: true, - 0xb9: true, - 0xba: true, - 0xbb: true, - 0xbc: true, - 0xbd: true, - 0xbe: true, - 0xbf: true, - 0xc0: true, - 0xc1: true, - 0xc2: true, - 0xc3: true, - 0xc4: true, - 0xc5: true, - 0xc6: true, - 0xc7: true, - 0xc8: true, - 0xc9: true, - 0xca: true, - 0xcb: true, - 0xcc: true, - 0xcd: true, - 0xce: true, - 0xcf: true, - 0xd0: true, - 0xd1: true, - 0xd2: true, - 0xd3: true, - 0xd4: true, - 0xd5: true, - 0xd6: true, - 0xd7: true, - 0xd8: true, - 0xd9: true, - 0xda: true, - 0xdb: true, - 0xdc: true, - 0xdd: true, - 0xde: true, - 0xdf: true, - 0xe0: true, - 0xe1: true, - 0xe2: true, - 0xe3: true, - 0xe4: true, - 0xe5: true, - 0xe6: true, - 0xe7: true, - 0xe8: true, - 0xe9: true, - 0xea: true, - 0xeb: true, - 0xec: true, - 0xed: true, - 0xee: true, - 0xef: true, - 0xf0: true, - 0xf1: true, - 0xf2: true, - 0xf3: true, - 0xf4: true, - 0xf5: true, - 0xf6: true, - 0xf7: true, - 0xf8: true, - 0xf9: true, - 0xfa: true, - 0xfb: true, - 0xfc: true, - 0xfd: true, - 0xfe: true, - 0xff: true, -} - -var hex = "0123456789abcdef" - -// escapeIndex finds the index of the first char in `s` that requires escaping. -// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if -// it includes a double quote or backslash. -// If no chars in `s` require escaping, the return value is -1. -func escapeIndex(s string) int { - chunks := stringToUint64Slice(s) - for _, n := range chunks { - // combine masks before checking for the MSB of each byte. We include - // `n` in the mask to check whether any of the *input* byte MSBs were - // set (i.e. the byte was outside the ASCII range). - mask := n | below(n, 0x20) | contains(n, '"') | contains(n, '\\') - if (mask & msb) != 0 { - return bits.TrailingZeros64(mask&msb) / 8 - } - } - - valLen := len(s) - for i := len(chunks) * 8; i < valLen; i++ { - if needEscape[s[i]] { - return i - } - } - - return -1 -} - -// below return a mask that can be used to determine if any of the bytes -// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was -// below `b`. The result is only valid if `b`, and each byte in `n`, is below -// 0x80. -func below(n uint64, b byte) uint64 { - return n - expand(b) -} - -// contains returns a mask that can be used to determine if any of the -// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then -// that byte is equal to `b`. The result is only valid if `b`, and each -// byte in `n`, is below 0x80. -func contains(n uint64, b byte) uint64 { - return (n ^ expand(b)) - lsb -} - -// expand puts the specified byte into each of the 8 bytes of a uint64. -func expand(b byte) uint64 { - return lsb * uint64(b) -} - -//nolint:govet -func stringToUint64Slice(s string) []uint64 { - return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{ - Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data, - Len: len(s) / 8, - Cap: len(s) / 8, - })) -} - -func encodeEscapedString(buf []byte, s string) []byte { - valLen := len(s) - if valLen == 0 { - return append(buf, `""`...) - } - buf = append(buf, '"') - var ( - i, j int - ) - if valLen >= 8 { - chunks := stringToUint64Slice(s) - for _, n := range chunks { - // combine masks before checking for the MSB of each byte. We include - // `n` in the mask to check whether any of the *input* byte MSBs were - // set (i.e. the byte was outside the ASCII range). - mask := n | (n - (lsb * 0x20)) | - ((n ^ (lsb * '"')) - lsb) | - ((n ^ (lsb * '\\')) - lsb) | - ((n ^ (lsb * '<')) - lsb) | - ((n ^ (lsb * '>')) - lsb) | - ((n ^ (lsb * '&')) - lsb) - if (mask & msb) != 0 { - j = bits.TrailingZeros64(mask&msb) / 8 - goto ESCAPE_END - } - } - for i := len(chunks) * 8; i < valLen; i++ { - if needEscapeWithHTML[s[i]] { - j = i - goto ESCAPE_END - } - } - // no found any escape characters. - return append(append(buf, s...), '"') - } -ESCAPE_END: - for j < valLen { - c := s[j] - - if !needEscapeWithHTML[c] { - // fast path: most of the time, printable ascii characters are used - j++ - continue - } - - switch c { - case '\\', '"': - buf = append(buf, s[i:j]...) - buf = append(buf, '\\', c) - i = j + 1 - j = j + 1 - continue - - case '\n': - buf = append(buf, s[i:j]...) - buf = append(buf, '\\', 'n') - i = j + 1 - j = j + 1 - continue - - case '\r': - buf = append(buf, s[i:j]...) - buf = append(buf, '\\', 'r') - i = j + 1 - j = j + 1 - continue - - case '\t': - buf = append(buf, s[i:j]...) - buf = append(buf, '\\', 't') - i = j + 1 - j = j + 1 - continue - - case '<', '>', '&': - buf = append(buf, s[i:j]...) - buf = append(buf, `\u00`...) - buf = append(buf, hex[c>>4], hex[c&0xF]) - i = j + 1 - j = j + 1 - continue - } - - // This encodes bytes < 0x20 except for \t, \n and \r. - if c < 0x20 { - buf = append(buf, s[i:j]...) - buf = append(buf, `\u00`...) - buf = append(buf, hex[c>>4], hex[c&0xF]) - i = j + 1 - j = j + 1 - continue - } - - r, size := utf8.DecodeRuneInString(s[j:]) - - if r == utf8.RuneError && size == 1 { - buf = append(buf, s[i:j]...) - buf = append(buf, `\ufffd`...) - i = j + size - j = j + size - continue - } - - switch r { - case '\u2028', '\u2029': - // U+2028 is LINE SEPARATOR. - // U+2029 is PARAGRAPH SEPARATOR. - // They are both technically valid characters in JSON strings, - // but don't work in JSONP, which has to be evaluated as JavaScript, - // and can lead to security holes there. It is valid JSON to - // escape them, so we do so unconditionally. - // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. - buf = append(buf, s[i:j]...) - buf = append(buf, `\u202`...) - buf = append(buf, hex[r&0xF]) - i = j + size - j = j + size - continue - } - - j += size - } - - return append(append(buf, s[i:]...), '"') -} - -func encodeNoEscapedString(buf []byte, s string) []byte { - valLen := len(s) - if valLen == 0 { - return append(buf, `""`...) - } - buf = append(buf, '"') - var escapeIdx int - if valLen >= 8 { - if escapeIdx = escapeIndex(s); escapeIdx < 0 { - return append(append(buf, s...), '"') - } - } - - i := 0 - j := escapeIdx - for j < valLen { - c := s[j] - - if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' { - // fast path: most of the time, printable ascii characters are used - j++ - continue - } - - switch c { - case '\\', '"': - buf = append(buf, s[i:j]...) - buf = append(buf, '\\', c) - i = j + 1 - j = j + 1 - continue - - case '\n': - buf = append(buf, s[i:j]...) - buf = append(buf, '\\', 'n') - i = j + 1 - j = j + 1 - continue - - case '\r': - buf = append(buf, s[i:j]...) - buf = append(buf, '\\', 'r') - i = j + 1 - j = j + 1 - continue - - case '\t': - buf = append(buf, s[i:j]...) - buf = append(buf, '\\', 't') - i = j + 1 - j = j + 1 - continue - - case '<', '>', '&': - buf = append(buf, s[i:j]...) - buf = append(buf, `\u00`...) - buf = append(buf, hex[c>>4], hex[c&0xF]) - i = j + 1 - j = j + 1 - continue - } - - // This encodes bytes < 0x20 except for \t, \n and \r. - if c < 0x20 { - buf = append(buf, s[i:j]...) - buf = append(buf, `\u00`...) - buf = append(buf, hex[c>>4], hex[c&0xF]) - i = j + 1 - j = j + 1 - continue - } - - r, size := utf8.DecodeRuneInString(s[j:]) - - if r == utf8.RuneError && size == 1 { - buf = append(buf, s[i:j]...) - buf = append(buf, `\ufffd`...) - i = j + size - j = j + size - continue - } - - switch r { - case '\u2028', '\u2029': - // U+2028 is LINE SEPARATOR. - // U+2029 is PARAGRAPH SEPARATOR. - // They are both technically valid characters in JSON strings, - // but don't work in JSONP, which has to be evaluated as JavaScript, - // and can lead to security holes there. It is valid JSON to - // escape them, so we do so unconditionally. - // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. - buf = append(buf, s[i:j]...) - buf = append(buf, `\u202`...) - buf = append(buf, hex[r&0xF]) - i = j + size - j = j + size - continue - } - - j += size - } - - return append(append(buf, s[i:]...), '"') -} diff --git a/encode_vm.go b/encode_vm.go deleted file mode 100644 index 3893ce1..0000000 --- a/encode_vm.go +++ /dev/null @@ -1,66 +0,0 @@ -package json - -import ( - "fmt" - "reflect" - "strconv" - "unsafe" -) - -const startDetectingCyclesAfter = 1000 - -func load(base uintptr, idx uintptr) uintptr { - addr := base + idx - return **(**uintptr)(unsafe.Pointer(&addr)) -} - -func store(base uintptr, idx uintptr, p uintptr) { - addr := base + idx - **(**uintptr)(unsafe.Pointer(&addr)) = p -} - -func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } -func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } -func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } -func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } -func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } -func ptrToNumber(p uintptr) Number { return **(**Number)(unsafe.Pointer(&p)) } -func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } -func ptrToSlice(p uintptr) *sliceHeader { return *(**sliceHeader)(unsafe.Pointer(&p)) } -func ptrToPtr(p uintptr) uintptr { - return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) -} -func ptrToUnsafePtr(p uintptr) unsafe.Pointer { - return *(*unsafe.Pointer)(unsafe.Pointer(&p)) -} -func ptrToInterface(code *opcode, p uintptr) interface{} { - return *(*interface{})(unsafe.Pointer(&emptyInterface{ - typ: code.typ, - ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), - })) -} - -func errUnsupportedValue(code *opcode, ptr uintptr) *UnsupportedValueError { - v := *(*interface{})(unsafe.Pointer(&emptyInterface{ - typ: code.typ, - ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)), - })) - return &UnsupportedValueError{ - Value: reflect.ValueOf(v), - Str: fmt.Sprintf("encountered a cycle via %s", code.typ), - } -} - -func errUnsupportedFloat(v float64) *UnsupportedValueError { - return &UnsupportedValueError{ - Value: reflect.ValueOf(v), - Str: strconv.FormatFloat(v, 'g', -1, 64), - } -} - -func errMarshalerWithCode(code *opcode, err error) *MarshalerError { - return &MarshalerError{ - Type: rtype2type(code.typ), - Err: err, - } -} diff --git a/internal/encoder/compact.go b/internal/encoder/compact.go index e5c5793..cf3f7fa 100644 --- a/internal/encoder/compact.go +++ b/internal/encoder/compact.go @@ -6,7 +6,7 @@ import ( "github.com/goccy/go-json/internal/errors" ) -func compact(dst *bytes.Buffer, src []byte, escape bool) error { +func Compact(dst *bytes.Buffer, src []byte, escape bool) error { if len(src) == 0 { return errors.ErrUnexpectedEndOfJSON("", 0) } diff --git a/encode_opcode_test.go b/internal/encoder/encode_opcode_test.go similarity index 73% rename from encode_opcode_test.go rename to internal/encoder/encode_opcode_test.go index 96d3a3d..d37d747 100644 --- a/encode_opcode_test.go +++ b/internal/encoder/encode_opcode_test.go @@ -1,4 +1,4 @@ -package json +package encoder import ( "testing" @@ -10,9 +10,9 @@ func TestDumpOpcode(t *testing.T) { header := (*emptyInterface)(unsafe.Pointer(&v)) typ := header.typ typeptr := uintptr(unsafe.Pointer(typ)) - codeSet, err := encodeCompileToGetCodeSet(typeptr) + codeSet, err := CompileToGetCodeSet(typeptr) if err != nil { t.Fatal(err) } - codeSet.code.dump() + codeSet.Code.Dump() } diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index b8baf49..ad9ced5 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -434,7 +434,7 @@ func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]by } buf := bytes.NewBuffer(b) // TODO: we should validate buffer with `compact` - if err := compact(buf, bb, escape); err != nil { + if err := Compact(buf, bb, escape); err != nil { return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} } return buf.Bytes(), nil @@ -461,11 +461,11 @@ func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v inte return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} } var compactBuf bytes.Buffer - if err := compact(&compactBuf, bb, escape); err != nil { + if err := Compact(&compactBuf, bb, escape); err != nil { return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} } var indentBuf bytes.Buffer - if err := encodeIndent( + if err := Indent( &indentBuf, compactBuf.Bytes(), string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+indent+1), diff --git a/internal/encoder/indent.go b/internal/encoder/indent.go index ac76159..fba4519 100644 --- a/internal/encoder/indent.go +++ b/internal/encoder/indent.go @@ -6,7 +6,7 @@ import ( "github.com/goccy/go-json/internal/errors" ) -func encodeIndent(dst *bytes.Buffer, src []byte, prefix, indentStr string) error { +func Indent(dst *bytes.Buffer, src []byte, prefix, indentStr string) error { length := int64(len(src)) indentNum := 0 indentBytes := []byte(indentStr) diff --git a/json.go b/json.go index d4a92d6..3ebba68 100644 --- a/json.go +++ b/json.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/json" "errors" + + "github.com/goccy/go-json/internal/encoder" ) // Marshaler is the interface implemented by types that @@ -308,7 +310,7 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error { // Compact appends to dst the JSON-encoded src with // insignificant space characters elided. func Compact(dst *bytes.Buffer, src []byte) error { - return compact(dst, src, false) + return encoder.Compact(dst, src, false) } // Indent appends to dst an indented form of the JSON-encoded src. @@ -323,7 +325,7 @@ func Compact(dst *bytes.Buffer, src []byte) error { // For example, if src has no trailing spaces, neither will dst; // if src ends in a trailing newline, so will dst. func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { - return encodeWithIndent(dst, src, prefix, indent) + return encoder.Indent(dst, src, prefix, indent) } // HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 From 969dfcec3129a5ada48c8df0e55271da404d5abd Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 16:17:14 +0900 Subject: [PATCH 09/15] Reduce memory usage at compile time --- docker-compose.yml | 2 +- internal/encoder/vm/vm.go | 6 ++++++ internal/encoder/vm_escaped/vm.go | 6 ++++++ internal/encoder/vm_indent/vm.go | 6 ++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 68f12b1..eca4f22 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: deploy: resources: limits: - memory: 1200M + memory: 600M working_dir: /go/src/go-json command: | sh -c "go test -c . && ls go-json.test" diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 87651de..7d2ba7b 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -10,6 +10,12 @@ import ( "github.com/goccy/go-json/internal/encoder" "github.com/goccy/go-json/internal/runtime" + + // HACK: compile order + // `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent` packages uses a lot of memory to compile, + // so forcibly make dependencies and avoid compiling in concurrent. + // dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent + _ "github.com/goccy/go-json/internal/encoder/vm_escaped" ) const uintptrSize = 4 << (^uintptr(0) >> 63) diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go index 7843e6a..53eba06 100644 --- a/internal/encoder/vm_escaped/vm.go +++ b/internal/encoder/vm_escaped/vm.go @@ -10,6 +10,12 @@ import ( "github.com/goccy/go-json/internal/encoder" "github.com/goccy/go-json/internal/runtime" + + // HACK: compile order + // `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent` packages uses a lot of memory to compile, + // so forcibly make dependencies and avoid compiling in concurrent. + // dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent + _ "github.com/goccy/go-json/internal/encoder/vm_indent" ) const uintptrSize = 4 << (^uintptr(0) >> 63) diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index fcae72c..34f49a9 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -11,6 +11,12 @@ import ( "github.com/goccy/go-json/internal/encoder" "github.com/goccy/go-json/internal/runtime" + + // HACK: compile order + // `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent` packages uses a lot of memory to compile, + // so forcibly make dependencies and avoid compiling in concurrent. + // dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent + _ "github.com/goccy/go-json/internal/encoder/vm_escaped_indent" ) const uintptrSize = 4 << (^uintptr(0) >> 63) From 6a749c956b32c39c1f4a9ff7ca5400753acf525a Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 16:30:08 +0900 Subject: [PATCH 10/15] Fix error by linter --- .golangci.yml | 4 + decode_compile.go | 16 ++-- indent.go | 108 ----------------------- internal/encoder/vm/vm.go | 71 ++++++++------- internal/encoder/vm_escaped/vm.go | 71 ++++++++------- internal/encoder/vm_escaped_indent/vm.go | 73 ++++++++------- internal/encoder/vm_indent/vm.go | 73 ++++++++------- internal/runtime/rtype.go | 3 +- rtype.go | 4 - struct_field.go | 81 ----------------- 10 files changed, 157 insertions(+), 347 deletions(-) delete mode 100644 indent.go delete mode 100644 struct_field.go diff --git a/.golangci.yml b/.golangci.yml index 6bdcb8f..d667ce3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -62,6 +62,10 @@ issues: - path: rtype.go linters: - golint + - stylecheck + - path: error.go + linters: + - staticcheck # Maximum issues count per one linter. Set to 0 to disable. Default is 50. max-issues-per-linter: 0 diff --git a/decode_compile.go b/decode_compile.go index 8ec2fd0..67b2f0b 100644 --- a/decode_compile.go +++ b/decode_compile.go @@ -7,6 +7,8 @@ import ( "strings" "unicode" "unsafe" + + "github.com/goccy/go-json/internal/runtime" ) var ( @@ -327,16 +329,16 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD structName = typ.Name() for i := 0; i < fieldNum; i++ { field := typ.Field(i) - if isIgnoredStructField(field) { + if runtime.IsIgnoredStructField(field) { continue } isUnexportedField := unicode.IsLower([]rune(field.Name)[0]) - tag := structTagFromField(field) + tag := runtime.StructTagFromField(field) dec, err := decodeCompile(type2rtype(field.Type), structName, field.Name, structTypeToDecoder) if err != nil { return nil, err } - if field.Anonymous && !tag.isTaggedKey { + if field.Anonymous && !tag.IsTaggedKey { if stDec, ok := dec.(*structDecoder); ok { if type2rtype(field.Type) == typ { // recursive definition @@ -414,19 +416,19 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD } } } else { - if tag.isString { + if tag.IsString { dec = newWrappedStringDecoder(type2rtype(field.Type), dec, structName, field.Name) } var key string - if tag.key != "" { - key = tag.key + if tag.Key != "" { + key = tag.Key } else { key = field.Name } fieldSet := &structFieldSet{ dec: dec, offset: field.Offset, - isTaggedKey: tag.isTaggedKey, + isTaggedKey: tag.IsTaggedKey, key: key, keyLen: int64(len(key)), } diff --git a/indent.go b/indent.go deleted file mode 100644 index 31c28b1..0000000 --- a/indent.go +++ /dev/null @@ -1,108 +0,0 @@ -package json - -import "bytes" - -func encodeWithIndent(dst *bytes.Buffer, src []byte, prefix, indentStr string) error { - length := int64(len(src)) - indentNum := 0 - indentBytes := []byte(indentStr) - for cursor := int64(0); cursor < length; cursor++ { - c := src[cursor] - switch c { - case ' ', '\t', '\n', '\r': - continue - case '"': - if err := dst.WriteByte(c); err != nil { - return err - } - for { - cursor++ - if err := dst.WriteByte(src[cursor]); err != nil { - return err - } - switch src[cursor] { - case '\\': - cursor++ - if err := dst.WriteByte(src[cursor]); err != nil { - return err - } - case '"': - goto LOOP_END - case nul: - return errUnexpectedEndOfJSON("string", length) - } - } - case '{': - if cursor+1 < length && src[cursor+1] == '}' { - if _, err := dst.Write([]byte{'{', '}'}); err != nil { - return err - } - cursor++ - } else { - indentNum++ - b := []byte{c, '\n'} - b = append(b, prefix...) - b = append(b, bytes.Repeat(indentBytes, indentNum)...) - if _, err := dst.Write(b); err != nil { - return err - } - } - case '}': - indentNum-- - if indentNum < 0 { - return errInvalidCharacter('}', "}", cursor) - } - b := []byte{'\n'} - b = append(b, prefix...) - b = append(b, bytes.Repeat(indentBytes, indentNum)...) - b = append(b, c) - if _, err := dst.Write(b); err != nil { - return err - } - case '[': - if cursor+1 < length && src[cursor+1] == ']' { - if _, err := dst.Write([]byte{'[', ']'}); err != nil { - return err - } - cursor++ - } else { - indentNum++ - b := []byte{c, '\n'} - b = append(b, prefix...) - b = append(b, bytes.Repeat(indentBytes, indentNum)...) - if _, err := dst.Write(b); err != nil { - return err - } - } - case ']': - indentNum-- - if indentNum < 0 { - return errInvalidCharacter(']', "]", cursor) - } - b := []byte{'\n'} - b = append(b, prefix...) - b = append(b, bytes.Repeat(indentBytes, indentNum)...) - b = append(b, c) - if _, err := dst.Write(b); err != nil { - return err - } - case ':': - if _, err := dst.Write([]byte{':', ' '}); err != nil { - return err - } - case ',': - b := []byte{',', '\n'} - b = append(b, prefix...) - b = append(b, bytes.Repeat(indentBytes, indentNum)...) - if _, err := dst.Write(b); err != nil { - return err - } - default: - if err := dst.WriteByte(c); err != nil { - return err - } - } - LOOP_END: - } - return nil -} diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 7d2ba7b..a03459c 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -21,42 +21,41 @@ import ( const uintptrSize = 4 << (^uintptr(0) >> 63) var ( - load = encoder.Load - store = encoder.Store - loadNPtr = encoder.LoadNPtr - ptrToPtr = encoder.PtrToPtr - ptrToNPtr = encoder.PtrToNPtr - ptrToUnsafePtr = encoder.PtrToUnsafePtr - ptrToInterface = encoder.PtrToInterface - ptrToUint64 = encoder.PtrToUint64 - ptrToFloat32 = encoder.PtrToFloat32 - ptrToFloat64 = encoder.PtrToFloat64 - ptrToString = encoder.PtrToString - ptrToBool = encoder.PtrToBool - ptrToBytes = encoder.PtrToBytes - ptrToNumber = encoder.PtrToNumber - ptrToSlice = encoder.PtrToSlice - appendInt = encoder.AppendInt - appendUint = encoder.AppendUint - appendFloat32 = encoder.AppendFloat32 - appendFloat64 = encoder.AppendFloat64 - appendString = encoder.AppendString - appendBool = encoder.AppendBool - appendByteSlice = encoder.AppendByteSlice - appendNumber = encoder.AppendNumber - appendMarshalJSON = encoder.AppendMarshalJSON - appendMarshalText = encoder.AppendMarshalText - appendNull = encoder.AppendNull - appendComma = encoder.AppendComma - appendStructEnd = encoder.AppendStructEnd - errUnsupportedValue = encoder.ErrUnsupportedValue - errUnsupportedFloat = encoder.ErrUnsupportedFloat - errMarshalerWithCode = encoder.ErrMarshalerWithCode - mapiterinit = encoder.MapIterInit - mapiterkey = encoder.MapIterKey - mapitervalue = encoder.MapIterValue - mapiternext = encoder.MapIterNext - maplen = encoder.MapLen + load = encoder.Load + store = encoder.Store + loadNPtr = encoder.LoadNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSON + appendMarshalText = encoder.AppendMarshalText + appendNull = encoder.AppendNull + appendComma = encoder.AppendComma + appendStructEnd = encoder.AppendStructEnd + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen ) type emptyInterface struct { diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go index 53eba06..59edf0e 100644 --- a/internal/encoder/vm_escaped/vm.go +++ b/internal/encoder/vm_escaped/vm.go @@ -21,42 +21,41 @@ import ( const uintptrSize = 4 << (^uintptr(0) >> 63) var ( - load = encoder.Load - store = encoder.Store - loadNPtr = encoder.LoadNPtr - ptrToPtr = encoder.PtrToPtr - ptrToNPtr = encoder.PtrToNPtr - ptrToUnsafePtr = encoder.PtrToUnsafePtr - ptrToInterface = encoder.PtrToInterface - ptrToUint64 = encoder.PtrToUint64 - ptrToFloat32 = encoder.PtrToFloat32 - ptrToFloat64 = encoder.PtrToFloat64 - ptrToString = encoder.PtrToString - ptrToBool = encoder.PtrToBool - ptrToBytes = encoder.PtrToBytes - ptrToNumber = encoder.PtrToNumber - ptrToSlice = encoder.PtrToSlice - appendInt = encoder.AppendInt - appendUint = encoder.AppendUint - appendFloat32 = encoder.AppendFloat32 - appendFloat64 = encoder.AppendFloat64 - appendString = encoder.AppendEscapedString - appendBool = encoder.AppendBool - appendByteSlice = encoder.AppendByteSlice - appendNumber = encoder.AppendNumber - appendMarshalJSON = encoder.AppendMarshalJSON - appendMarshalText = encoder.AppendMarshalText - appendNull = encoder.AppendNull - appendComma = encoder.AppendComma - appendStructEnd = encoder.AppendStructEnd - errUnsupportedValue = encoder.ErrUnsupportedValue - errUnsupportedFloat = encoder.ErrUnsupportedFloat - errMarshalerWithCode = encoder.ErrMarshalerWithCode - mapiterinit = encoder.MapIterInit - mapiterkey = encoder.MapIterKey - mapitervalue = encoder.MapIterValue - mapiternext = encoder.MapIterNext - maplen = encoder.MapLen + load = encoder.Load + store = encoder.Store + loadNPtr = encoder.LoadNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendEscapedString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSON + appendMarshalText = encoder.AppendMarshalText + appendNull = encoder.AppendNull + appendComma = encoder.AppendComma + appendStructEnd = encoder.AppendStructEnd + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen ) type emptyInterface struct { diff --git a/internal/encoder/vm_escaped_indent/vm.go b/internal/encoder/vm_escaped_indent/vm.go index e64d975..992d1bc 100644 --- a/internal/encoder/vm_escaped_indent/vm.go +++ b/internal/encoder/vm_escaped_indent/vm.go @@ -16,43 +16,42 @@ import ( const uintptrSize = 4 << (^uintptr(0) >> 63) var ( - load = encoder.Load - store = encoder.Store - loadNPtr = encoder.LoadNPtr - ptrToPtr = encoder.PtrToPtr - ptrToNPtr = encoder.PtrToNPtr - ptrToUnsafePtr = encoder.PtrToUnsafePtr - ptrToInterface = encoder.PtrToInterface - ptrToUint64 = encoder.PtrToUint64 - ptrToFloat32 = encoder.PtrToFloat32 - ptrToFloat64 = encoder.PtrToFloat64 - ptrToString = encoder.PtrToString - ptrToBool = encoder.PtrToBool - ptrToBytes = encoder.PtrToBytes - ptrToNumber = encoder.PtrToNumber - ptrToSlice = encoder.PtrToSlice - appendInt = encoder.AppendInt - appendUint = encoder.AppendUint - appendFloat32 = encoder.AppendFloat32 - appendFloat64 = encoder.AppendFloat64 - appendString = encoder.AppendEscapedString - appendBool = encoder.AppendBool - appendByteSlice = encoder.AppendByteSlice - appendNumber = encoder.AppendNumber - appendMarshalJSON = encoder.AppendMarshalJSONIndent - appendMarshalText = encoder.AppendMarshalTextIndent - appendNull = encoder.AppendNull - appendComma = encoder.AppendCommaIndent - appendIndent = encoder.AppendIndent - appendStructEnd = encoder.AppendStructEndIndent - errUnsupportedValue = encoder.ErrUnsupportedValue - errUnsupportedFloat = encoder.ErrUnsupportedFloat - errMarshalerWithCode = encoder.ErrMarshalerWithCode - mapiterinit = encoder.MapIterInit - mapiterkey = encoder.MapIterKey - mapitervalue = encoder.MapIterValue - mapiternext = encoder.MapIterNext - maplen = encoder.MapLen + load = encoder.Load + store = encoder.Store + loadNPtr = encoder.LoadNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendEscapedString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSONIndent + appendMarshalText = encoder.AppendMarshalTextIndent + appendNull = encoder.AppendNull + appendComma = encoder.AppendCommaIndent + appendIndent = encoder.AppendIndent + appendStructEnd = encoder.AppendStructEndIndent + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen ) type emptyInterface struct { diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index 34f49a9..52e7869 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -22,43 +22,42 @@ import ( const uintptrSize = 4 << (^uintptr(0) >> 63) var ( - load = encoder.Load - store = encoder.Store - loadNPtr = encoder.LoadNPtr - ptrToPtr = encoder.PtrToPtr - ptrToNPtr = encoder.PtrToNPtr - ptrToUnsafePtr = encoder.PtrToUnsafePtr - ptrToInterface = encoder.PtrToInterface - ptrToUint64 = encoder.PtrToUint64 - ptrToFloat32 = encoder.PtrToFloat32 - ptrToFloat64 = encoder.PtrToFloat64 - ptrToString = encoder.PtrToString - ptrToBool = encoder.PtrToBool - ptrToBytes = encoder.PtrToBytes - ptrToNumber = encoder.PtrToNumber - ptrToSlice = encoder.PtrToSlice - appendInt = encoder.AppendInt - appendUint = encoder.AppendUint - appendFloat32 = encoder.AppendFloat32 - appendFloat64 = encoder.AppendFloat64 - appendString = encoder.AppendString - appendBool = encoder.AppendBool - appendByteSlice = encoder.AppendByteSlice - appendNumber = encoder.AppendNumber - appendMarshalJSON = encoder.AppendMarshalJSONIndent - appendMarshalText = encoder.AppendMarshalTextIndent - appendNull = encoder.AppendNull - appendComma = encoder.AppendCommaIndent - appendIndent = encoder.AppendIndent - appendStructEnd = encoder.AppendStructEndIndent - errUnsupportedValue = encoder.ErrUnsupportedValue - errUnsupportedFloat = encoder.ErrUnsupportedFloat - errMarshalerWithCode = encoder.ErrMarshalerWithCode - mapiterinit = encoder.MapIterInit - mapiterkey = encoder.MapIterKey - mapitervalue = encoder.MapIterValue - mapiternext = encoder.MapIterNext - maplen = encoder.MapLen + load = encoder.Load + store = encoder.Store + loadNPtr = encoder.LoadNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSONIndent + appendMarshalText = encoder.AppendMarshalTextIndent + appendNull = encoder.AppendNull + appendComma = encoder.AppendCommaIndent + appendIndent = encoder.AppendIndent + appendStructEnd = encoder.AppendStructEndIndent + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen ) type emptyInterface struct { diff --git a/internal/runtime/rtype.go b/internal/runtime/rtype.go index c73223d..4db10de 100644 --- a/internal/runtime/rtype.go +++ b/internal/runtime/rtype.go @@ -252,8 +252,9 @@ func IfaceIndir(*Type) bool //go:noescape func RType2Type(t *Type) reflect.Type +//go:nolint structcheck type emptyInterface struct { - typ *Type + _ *Type ptr unsafe.Pointer } diff --git a/rtype.go b/rtype.go index 6d06865..3459884 100644 --- a/rtype.go +++ b/rtype.go @@ -18,10 +18,6 @@ func rtype_ptrTo(t *rtype) *rtype { return runtime.PtrTo(t) } -func ifaceIndir(t *rtype) bool { - return runtime.IfaceIndir(t) -} - func rtype2type(t *rtype) reflect.Type { return runtime.RType2Type(t) } diff --git a/struct_field.go b/struct_field.go deleted file mode 100644 index 5a85cff..0000000 --- a/struct_field.go +++ /dev/null @@ -1,81 +0,0 @@ -package json - -import ( - "reflect" - "strings" - "unicode" -) - -func getTag(field reflect.StructField) string { - return field.Tag.Get("json") -} - -func isIgnoredStructField(field reflect.StructField) bool { - if field.PkgPath != "" { - if field.Anonymous { - if !(field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct) && field.Type.Kind() != reflect.Struct { - return true - } - } else { - // private field - return true - } - } - tag := getTag(field) - return tag == "-" -} - -type structTag struct { - key string - isTaggedKey bool - isOmitEmpty bool - isString bool - field reflect.StructField -} - -type structTags []*structTag - -func (t structTags) existsKey(key string) bool { - for _, tt := range t { - if tt.key == key { - return true - } - } - return false -} - -func isValidTag(s string) bool { - if s == "" { - return false - } - for _, c := range s { - switch { - case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): - // Backslash and quote chars are reserved, but - // otherwise any punctuation chars are allowed - // in a tag name. - case !unicode.IsLetter(c) && !unicode.IsDigit(c): - return false - } - } - return true -} - -func structTagFromField(field reflect.StructField) *structTag { - keyName := field.Name - tag := getTag(field) - st := &structTag{field: field} - opts := strings.Split(tag, ",") - if len(opts) > 0 { - if opts[0] != "" && isValidTag(opts[0]) { - keyName = opts[0] - st.isTaggedKey = true - } - } - st.key = keyName - if len(opts) > 1 { - st.isOmitEmpty = opts[1] == "omitempty" - st.isString = opts[1] == "string" - } - return st -} From 15071b164b7ec34c0edb53e7d3108e79820459fc Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 17:33:09 +0900 Subject: [PATCH 11/15] Fix `make cover` task --- Makefile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 75327d4..fd49bb1 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,20 @@ +PKG := github.com/goccy/go-json + BIN_DIR := $(CURDIR)/bin +PKGS := $(shell go list ./... | grep -v internal/cmd) +COVER_PKGS := $(foreach pkg,$(PKGS),$(subst $(PKG),.,$(pkg))) + +COMMA := , +EMPTY := +SPACE := $(EMPTY) $(EMPTY) +COVERPKG_OPT := $(subst $(SPACE),$(COMMA),$(COVER_PKGS)) $(BIN_DIR): @mkdir -p $(BIN_DIR) .PHONY: cover cover: - @ go test -coverprofile=cover.tmp.out . ; \ - cat cover.tmp.out | grep -v "encode_optype.go" > cover.out; \ - rm cover.tmp.out + go test -coverpkg=$(COVERPKG_OPT) -coverprofile=cover.out . .PHONY: cover-html cover-html: cover From c523402b11dce3a5b8931af73816d970b092bc41 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 17:51:23 +0900 Subject: [PATCH 12/15] Fix workflow for coverage --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 2fda7c1..8c5770a 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -42,7 +42,7 @@ jobs: - name: checkout uses: actions/checkout@v2 - name: measure coverage - run: go test -v -coverprofile=coverage.out ./ -count=1 + run: make cover - name: report coverage run: | bash <(curl -s https://codecov.io/bash) From 75d7b8e673f7f9bcef7207b78fd72b03beecbf91 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 18:23:58 +0900 Subject: [PATCH 13/15] Enable inline function call --- internal/encoder/vm/util.go | 78 +++++++++++++++++++ internal/encoder/vm/vm.go | 19 ----- internal/encoder/vm_escaped/util.go | 78 +++++++++++++++++++ internal/encoder/vm_escaped/vm.go | 19 ----- internal/encoder/vm_escaped_indent/util.go | 87 ++++++++++++++++++++++ internal/encoder/vm_escaped_indent/vm.go | 20 ----- internal/encoder/vm_indent/util.go | 87 ++++++++++++++++++++++ internal/encoder/vm_indent/vm.go | 20 ----- 8 files changed, 330 insertions(+), 78 deletions(-) create mode 100644 internal/encoder/vm/util.go create mode 100644 internal/encoder/vm_escaped/util.go create mode 100644 internal/encoder/vm_escaped_indent/util.go create mode 100644 internal/encoder/vm_indent/util.go diff --git a/internal/encoder/vm/util.go b/internal/encoder/vm/util.go new file mode 100644 index 0000000..d9c5449 --- /dev/null +++ b/internal/encoder/vm/util.go @@ -0,0 +1,78 @@ +package vm + +import ( + "encoding/json" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +func load(base uintptr, idx uintptr) uintptr { + addr := base + idx + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func store(base uintptr, idx uintptr, p uintptr) { + addr := base + idx + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { + addr := base + idx + p := **(**uintptr)(unsafe.Pointer(&addr)) + if p == 0 { + return 0 + } + return ptrToPtr(p) +} + +func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func ptrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func ptrToNPtr(p uintptr, ptrNum int) uintptr { + for i := 0; i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func appendBool(b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +func appendNull(b []byte) []byte { + return append(b, "null"...) +} + +func appendComma(b []byte) []byte { + return append(b, ',') +} + +func appendStructEnd(b []byte) []byte { + return append(b, '}', ',') +} diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index a03459c..248cc25 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -21,34 +21,15 @@ import ( const uintptrSize = 4 << (^uintptr(0) >> 63) var ( - load = encoder.Load - store = encoder.Store - loadNPtr = encoder.LoadNPtr - ptrToPtr = encoder.PtrToPtr - ptrToNPtr = encoder.PtrToNPtr - ptrToUnsafePtr = encoder.PtrToUnsafePtr - ptrToInterface = encoder.PtrToInterface - ptrToUint64 = encoder.PtrToUint64 - ptrToFloat32 = encoder.PtrToFloat32 - ptrToFloat64 = encoder.PtrToFloat64 - ptrToString = encoder.PtrToString - ptrToBool = encoder.PtrToBool - ptrToBytes = encoder.PtrToBytes - ptrToNumber = encoder.PtrToNumber - ptrToSlice = encoder.PtrToSlice appendInt = encoder.AppendInt appendUint = encoder.AppendUint appendFloat32 = encoder.AppendFloat32 appendFloat64 = encoder.AppendFloat64 appendString = encoder.AppendString - appendBool = encoder.AppendBool appendByteSlice = encoder.AppendByteSlice appendNumber = encoder.AppendNumber appendMarshalJSON = encoder.AppendMarshalJSON appendMarshalText = encoder.AppendMarshalText - appendNull = encoder.AppendNull - appendComma = encoder.AppendComma - appendStructEnd = encoder.AppendStructEnd errUnsupportedValue = encoder.ErrUnsupportedValue errUnsupportedFloat = encoder.ErrUnsupportedFloat mapiterinit = encoder.MapIterInit diff --git a/internal/encoder/vm_escaped/util.go b/internal/encoder/vm_escaped/util.go new file mode 100644 index 0000000..437154e --- /dev/null +++ b/internal/encoder/vm_escaped/util.go @@ -0,0 +1,78 @@ +package vm_escaped + +import ( + "encoding/json" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +func load(base uintptr, idx uintptr) uintptr { + addr := base + idx + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func store(base uintptr, idx uintptr, p uintptr) { + addr := base + idx + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { + addr := base + idx + p := **(**uintptr)(unsafe.Pointer(&addr)) + if p == 0 { + return 0 + } + return ptrToPtr(p) +} + +func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func ptrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func ptrToNPtr(p uintptr, ptrNum int) uintptr { + for i := 0; i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func appendBool(b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +func appendNull(b []byte) []byte { + return append(b, "null"...) +} + +func appendComma(b []byte) []byte { + return append(b, ',') +} + +func appendStructEnd(b []byte) []byte { + return append(b, '}', ',') +} diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go index 59edf0e..675effb 100644 --- a/internal/encoder/vm_escaped/vm.go +++ b/internal/encoder/vm_escaped/vm.go @@ -21,34 +21,15 @@ import ( const uintptrSize = 4 << (^uintptr(0) >> 63) var ( - load = encoder.Load - store = encoder.Store - loadNPtr = encoder.LoadNPtr - ptrToPtr = encoder.PtrToPtr - ptrToNPtr = encoder.PtrToNPtr - ptrToUnsafePtr = encoder.PtrToUnsafePtr - ptrToInterface = encoder.PtrToInterface - ptrToUint64 = encoder.PtrToUint64 - ptrToFloat32 = encoder.PtrToFloat32 - ptrToFloat64 = encoder.PtrToFloat64 - ptrToString = encoder.PtrToString - ptrToBool = encoder.PtrToBool - ptrToBytes = encoder.PtrToBytes - ptrToNumber = encoder.PtrToNumber - ptrToSlice = encoder.PtrToSlice appendInt = encoder.AppendInt appendUint = encoder.AppendUint appendFloat32 = encoder.AppendFloat32 appendFloat64 = encoder.AppendFloat64 appendString = encoder.AppendEscapedString - appendBool = encoder.AppendBool appendByteSlice = encoder.AppendByteSlice appendNumber = encoder.AppendNumber appendMarshalJSON = encoder.AppendMarshalJSON appendMarshalText = encoder.AppendMarshalText - appendNull = encoder.AppendNull - appendComma = encoder.AppendComma - appendStructEnd = encoder.AppendStructEnd errUnsupportedValue = encoder.ErrUnsupportedValue errUnsupportedFloat = encoder.ErrUnsupportedFloat mapiterinit = encoder.MapIterInit diff --git a/internal/encoder/vm_escaped_indent/util.go b/internal/encoder/vm_escaped_indent/util.go new file mode 100644 index 0000000..ba004cd --- /dev/null +++ b/internal/encoder/vm_escaped_indent/util.go @@ -0,0 +1,87 @@ +package vm_escaped_indent + +import ( + "bytes" + "encoding/json" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +func load(base uintptr, idx uintptr) uintptr { + addr := base + idx + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func store(base uintptr, idx uintptr, p uintptr) { + addr := base + idx + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { + addr := base + idx + p := **(**uintptr)(unsafe.Pointer(&addr)) + if p == 0 { + return 0 + } + return ptrToPtr(p) +} + +func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func ptrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func ptrToNPtr(p uintptr, ptrNum int) uintptr { + for i := 0; i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func appendBool(b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +func appendNull(b []byte) []byte { + return append(b, "null"...) +} + +func appendComma(b []byte) []byte { + return append(b, ',', '\n') +} + +func appendStructEnd(ctx *encoder.RuntimeContext, b []byte, indent int) []byte { + b = append(b, '\n') + b = append(b, ctx.Prefix...) + b = append(b, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+indent)...) + return append(b, '}', ',', '\n') +} + +func appendIndent(ctx *encoder.RuntimeContext, b []byte, indent int) []byte { + b = append(b, ctx.Prefix...) + return append(b, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+indent)...) +} diff --git a/internal/encoder/vm_escaped_indent/vm.go b/internal/encoder/vm_escaped_indent/vm.go index 992d1bc..d1cccde 100644 --- a/internal/encoder/vm_escaped_indent/vm.go +++ b/internal/encoder/vm_escaped_indent/vm.go @@ -16,35 +16,15 @@ import ( const uintptrSize = 4 << (^uintptr(0) >> 63) var ( - load = encoder.Load - store = encoder.Store - loadNPtr = encoder.LoadNPtr - ptrToPtr = encoder.PtrToPtr - ptrToNPtr = encoder.PtrToNPtr - ptrToUnsafePtr = encoder.PtrToUnsafePtr - ptrToInterface = encoder.PtrToInterface - ptrToUint64 = encoder.PtrToUint64 - ptrToFloat32 = encoder.PtrToFloat32 - ptrToFloat64 = encoder.PtrToFloat64 - ptrToString = encoder.PtrToString - ptrToBool = encoder.PtrToBool - ptrToBytes = encoder.PtrToBytes - ptrToNumber = encoder.PtrToNumber - ptrToSlice = encoder.PtrToSlice appendInt = encoder.AppendInt appendUint = encoder.AppendUint appendFloat32 = encoder.AppendFloat32 appendFloat64 = encoder.AppendFloat64 appendString = encoder.AppendEscapedString - appendBool = encoder.AppendBool appendByteSlice = encoder.AppendByteSlice appendNumber = encoder.AppendNumber appendMarshalJSON = encoder.AppendMarshalJSONIndent appendMarshalText = encoder.AppendMarshalTextIndent - appendNull = encoder.AppendNull - appendComma = encoder.AppendCommaIndent - appendIndent = encoder.AppendIndent - appendStructEnd = encoder.AppendStructEndIndent errUnsupportedValue = encoder.ErrUnsupportedValue errUnsupportedFloat = encoder.ErrUnsupportedFloat mapiterinit = encoder.MapIterInit diff --git a/internal/encoder/vm_indent/util.go b/internal/encoder/vm_indent/util.go new file mode 100644 index 0000000..dcf976e --- /dev/null +++ b/internal/encoder/vm_indent/util.go @@ -0,0 +1,87 @@ +package vm_indent + +import ( + "bytes" + "encoding/json" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +func load(base uintptr, idx uintptr) uintptr { + addr := base + idx + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func store(base uintptr, idx uintptr, p uintptr) { + addr := base + idx + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { + addr := base + idx + p := **(**uintptr)(unsafe.Pointer(&addr)) + if p == 0 { + return 0 + } + return ptrToPtr(p) +} + +func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func ptrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func ptrToNPtr(p uintptr, ptrNum int) uintptr { + for i := 0; i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func appendBool(b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +func appendNull(b []byte) []byte { + return append(b, "null"...) +} + +func appendComma(b []byte) []byte { + return append(b, ',', '\n') +} + +func appendStructEnd(ctx *encoder.RuntimeContext, b []byte, indent int) []byte { + b = append(b, '\n') + b = append(b, ctx.Prefix...) + b = append(b, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+indent)...) + return append(b, '}', ',', '\n') +} + +func appendIndent(ctx *encoder.RuntimeContext, b []byte, indent int) []byte { + b = append(b, ctx.Prefix...) + return append(b, bytes.Repeat(ctx.IndentStr, ctx.BaseIndent+indent)...) +} diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index 52e7869..026bd7a 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -22,35 +22,15 @@ import ( const uintptrSize = 4 << (^uintptr(0) >> 63) var ( - load = encoder.Load - store = encoder.Store - loadNPtr = encoder.LoadNPtr - ptrToPtr = encoder.PtrToPtr - ptrToNPtr = encoder.PtrToNPtr - ptrToUnsafePtr = encoder.PtrToUnsafePtr - ptrToInterface = encoder.PtrToInterface - ptrToUint64 = encoder.PtrToUint64 - ptrToFloat32 = encoder.PtrToFloat32 - ptrToFloat64 = encoder.PtrToFloat64 - ptrToString = encoder.PtrToString - ptrToBool = encoder.PtrToBool - ptrToBytes = encoder.PtrToBytes - ptrToNumber = encoder.PtrToNumber - ptrToSlice = encoder.PtrToSlice appendInt = encoder.AppendInt appendUint = encoder.AppendUint appendFloat32 = encoder.AppendFloat32 appendFloat64 = encoder.AppendFloat64 appendString = encoder.AppendString - appendBool = encoder.AppendBool appendByteSlice = encoder.AppendByteSlice appendNumber = encoder.AppendNumber appendMarshalJSON = encoder.AppendMarshalJSONIndent appendMarshalText = encoder.AppendMarshalTextIndent - appendNull = encoder.AppendNull - appendComma = encoder.AppendCommaIndent - appendIndent = encoder.AppendIndent - appendStructEnd = encoder.AppendStructEndIndent errUnsupportedValue = encoder.ErrUnsupportedValue errUnsupportedFloat = encoder.ErrUnsupportedFloat mapiterinit = encoder.MapIterInit From e0812246ef3640cde2e5b5685f0dbb1183f5a0aa Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 18:29:18 +0900 Subject: [PATCH 14/15] Fix test code for debug --- decode_test.go | 136 +++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/decode_test.go b/decode_test.go index c942e66..7d933c2 100644 --- a/decode_test.go +++ b/decode_test.go @@ -1786,80 +1786,82 @@ func equalError(a, b error) bool { func TestUnmarshal(t *testing.T) { for i, tt := range unmarshalTests { - in := []byte(tt.in) - if tt.ptr == nil { - continue - } - - typ := reflect.TypeOf(tt.ptr) - if typ.Kind() != reflect.Ptr { - t.Errorf("#%d: unmarshalTest.ptr %T is not a pointer type", i, tt.ptr) - continue - } - typ = typ.Elem() - - // v = new(right-type) - v := reflect.New(typ) - - if !reflect.DeepEqual(tt.ptr, v.Interface()) { - // There's no reason for ptr to point to non-zero data, - // as we decode into new(right-type), so the data is - // discarded. - // This can easily mean tests that silently don't test - // what they should. To test decoding into existing - // data, see TestPrefilled. - t.Errorf("#%d: unmarshalTest.ptr %#v is not a pointer to a zero value", i, tt.ptr) - continue - } - - dec := json.NewDecoder(bytes.NewReader(in)) - if tt.useNumber { - dec.UseNumber() - } - if tt.disallowUnknownFields { - dec.DisallowUnknownFields() - } - if err := dec.Decode(v.Interface()); !equalError(err, tt.err) { - t.Errorf("#%d: %v, want %v", i, err, tt.err) - continue - } else if err != nil { - continue - } - if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { - t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out) - data, _ := json.Marshal(v.Elem().Interface()) - println(string(data)) - data, _ = json.Marshal(tt.out) - println(string(data)) - continue - } - - // Check round trip also decodes correctly. - if tt.err == nil { - enc, err := json.Marshal(v.Interface()) - if err != nil { - t.Errorf("#%d: error re-marshaling: %v", i, err) - continue + t.Run(fmt.Sprintf("%d_%q", i, tt.in), func(t *testing.T) { + in := []byte(tt.in) + if tt.ptr == nil { + return } - if tt.golden && !bytes.Equal(enc, in) { - t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in) + + typ := reflect.TypeOf(tt.ptr) + if typ.Kind() != reflect.Ptr { + t.Errorf("#%d: unmarshalTest.ptr %T is not a pointer type", i, tt.ptr) + return } - vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) - dec = json.NewDecoder(bytes.NewReader(enc)) + typ = typ.Elem() + + // v = new(right-type) + v := reflect.New(typ) + + if !reflect.DeepEqual(tt.ptr, v.Interface()) { + // There's no reason for ptr to point to non-zero data, + // as we decode into new(right-type), so the data is + // discarded. + // This can easily mean tests that silently don't test + // what they should. To test decoding into existing + // data, see TestPrefilled. + t.Errorf("#%d: unmarshalTest.ptr %#v is not a pointer to a zero value", i, tt.ptr) + return + } + + dec := json.NewDecoder(bytes.NewReader(in)) if tt.useNumber { dec.UseNumber() } - if err := dec.Decode(vv.Interface()); err != nil { - t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err) - continue + if tt.disallowUnknownFields { + dec.DisallowUnknownFields() } - if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) { - t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface()) - t.Errorf(" In: %q", strings.Map(noSpace, string(in))) - t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc))) - continue + if err := dec.Decode(v.Interface()); !equalError(err, tt.err) { + t.Errorf("#%d: %v, want %v", i, err, tt.err) + return + } else if err != nil { + return } - } + if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { + t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out) + data, _ := json.Marshal(v.Elem().Interface()) + println(string(data)) + data, _ = json.Marshal(tt.out) + println(string(data)) + return + } + + // Check round trip also decodes correctly. + if tt.err == nil { + enc, err := json.Marshal(v.Interface()) + if err != nil { + t.Errorf("#%d: error re-marshaling: %v", i, err) + return + } + if tt.golden && !bytes.Equal(enc, in) { + t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in) + } + vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) + dec = json.NewDecoder(bytes.NewReader(enc)) + if tt.useNumber { + dec.UseNumber() + } + if err := dec.Decode(vv.Interface()); err != nil { + t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err) + return + } + if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) { + t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface()) + t.Errorf(" In: %q", strings.Map(noSpace, string(in))) + t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc))) + return + } + } + }) } } From d2d7e6d3679cea0eb59290d627d41a449d382b2a Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 18 Mar 2021 18:31:45 +0900 Subject: [PATCH 15/15] Fix error by linter --- internal/encoder/vm/util.go | 2 +- internal/encoder/vm_escaped/util.go | 2 +- internal/encoder/vm_escaped_indent/util.go | 2 +- internal/encoder/vm_indent/util.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/encoder/vm/util.go b/internal/encoder/vm/util.go index d9c5449..e3ab131 100644 --- a/internal/encoder/vm/util.go +++ b/internal/encoder/vm/util.go @@ -18,7 +18,7 @@ func store(base uintptr, idx uintptr, p uintptr) { **(**uintptr)(unsafe.Pointer(&addr)) = p } -func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { +func loadNPtr(base uintptr, idx uintptr, _ int) uintptr { addr := base + idx p := **(**uintptr)(unsafe.Pointer(&addr)) if p == 0 { diff --git a/internal/encoder/vm_escaped/util.go b/internal/encoder/vm_escaped/util.go index 437154e..2bf9be9 100644 --- a/internal/encoder/vm_escaped/util.go +++ b/internal/encoder/vm_escaped/util.go @@ -18,7 +18,7 @@ func store(base uintptr, idx uintptr, p uintptr) { **(**uintptr)(unsafe.Pointer(&addr)) = p } -func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { +func loadNPtr(base uintptr, idx uintptr, _ int) uintptr { addr := base + idx p := **(**uintptr)(unsafe.Pointer(&addr)) if p == 0 { diff --git a/internal/encoder/vm_escaped_indent/util.go b/internal/encoder/vm_escaped_indent/util.go index ba004cd..fc26d4d 100644 --- a/internal/encoder/vm_escaped_indent/util.go +++ b/internal/encoder/vm_escaped_indent/util.go @@ -19,7 +19,7 @@ func store(base uintptr, idx uintptr, p uintptr) { **(**uintptr)(unsafe.Pointer(&addr)) = p } -func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { +func loadNPtr(base uintptr, idx uintptr, _ int) uintptr { addr := base + idx p := **(**uintptr)(unsafe.Pointer(&addr)) if p == 0 { diff --git a/internal/encoder/vm_indent/util.go b/internal/encoder/vm_indent/util.go index dcf976e..9c68aae 100644 --- a/internal/encoder/vm_indent/util.go +++ b/internal/encoder/vm_indent/util.go @@ -19,7 +19,7 @@ func store(base uintptr, idx uintptr, p uintptr) { **(**uintptr)(unsafe.Pointer(&addr)) = p } -func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { +func loadNPtr(base uintptr, idx uintptr, _ int) uintptr { addr := base + idx p := **(**uintptr)(unsafe.Pointer(&addr)) if p == 0 {