mirror of https://github.com/goccy/go-json.git
Merge pull request #225 from goccy/feature/refactor-vm
Refactor the VM source for encoding ( use the same source for each VM )
This commit is contained in:
commit
bbea516a68
|
@ -1450,7 +1450,6 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
|
||||||
}
|
}
|
||||||
fieldIdx++
|
fieldIdx++
|
||||||
}
|
}
|
||||||
ctx = ctx.decIndent()
|
|
||||||
|
|
||||||
structEndCode := &Opcode{
|
structEndCode := &Opcode{
|
||||||
Op: OpStructEnd,
|
Op: OpStructEnd,
|
||||||
|
@ -1459,6 +1458,8 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
|
||||||
Next: newEndOp(ctx),
|
Next: newEndOp(ctx),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx = ctx.decIndent()
|
||||||
|
|
||||||
// no struct field
|
// no struct field
|
||||||
if head == nil {
|
if head == nil {
|
||||||
head = &Opcode{
|
head = &Opcode{
|
||||||
|
|
|
@ -390,7 +390,7 @@ func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{
|
||||||
return compactedBuf, nil
|
return compactedBuf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}, indent int, escape bool) ([]byte, error) {
|
func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) {
|
||||||
rv := reflect.ValueOf(v) // convert by dynamic interface type
|
rv := reflect.ValueOf(v) // convert by dynamic interface type
|
||||||
if code.AddrForMarshaler {
|
if code.AddrForMarshaler {
|
||||||
if rv.CanAddr() {
|
if rv.CanAddr() {
|
||||||
|
@ -415,7 +415,7 @@ func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v inte
|
||||||
indentedBuf, err := doIndent(
|
indentedBuf, err := doIndent(
|
||||||
b,
|
b,
|
||||||
marshalBuf,
|
marshalBuf,
|
||||||
string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+indent),
|
string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+code.Indent),
|
||||||
string(ctx.IndentStr),
|
string(ctx.IndentStr),
|
||||||
escape,
|
escape,
|
||||||
)
|
)
|
||||||
|
@ -494,10 +494,10 @@ func AppendStructEnd(b []byte) []byte {
|
||||||
return append(b, '}', ',')
|
return append(b, '}', ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppendStructEndIndent(ctx *RuntimeContext, b []byte, indent int) []byte {
|
func AppendStructEndIndent(ctx *RuntimeContext, code *Opcode, b []byte) []byte {
|
||||||
b = append(b, '\n')
|
b = append(b, '\n')
|
||||||
b = append(b, ctx.Prefix...)
|
b = append(b, ctx.Prefix...)
|
||||||
indentNum := ctx.BaseIndent + indent
|
indentNum := ctx.BaseIndent + code.Indent - 1
|
||||||
for i := 0; i < indentNum; i++ {
|
for i := 0; i < indentNum; i++ {
|
||||||
b = append(b, ctx.IndentStr...)
|
b = append(b, ctx.IndentStr...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
// HACK: compile order
|
||||||
|
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` 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 => vm_debug
|
||||||
|
_ "github.com/goccy/go-json/internal/encoder/vm_escaped"
|
||||||
|
)
|
|
@ -2,12 +2,41 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appendInt = encoder.AppendInt
|
||||||
|
appendUint = encoder.AppendUint
|
||||||
|
appendFloat32 = encoder.AppendFloat32
|
||||||
|
appendFloat64 = encoder.AppendFloat64
|
||||||
|
appendString = encoder.AppendString
|
||||||
|
appendByteSlice = encoder.AppendByteSlice
|
||||||
|
appendNumber = encoder.AppendNumber
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
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 errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder: opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
func load(base uintptr, idx uintptr) uintptr {
|
func load(base uintptr, idx uintptr) uintptr {
|
||||||
addr := base + idx
|
addr := base + idx
|
||||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
@ -76,23 +105,111 @@ func appendComma(b []byte) []byte {
|
||||||
return append(b, ',')
|
return append(b, ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
func appendColon(b []byte) []byte {
|
||||||
return append(b, code.Key...)
|
last := len(b) - 1
|
||||||
|
b[last] = ':'
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = append(b, key...)
|
||||||
|
b[len(b)-1] = ':'
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
b[len(b)-1] = '}'
|
||||||
|
b = append(b, ',')
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, _ *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||||
|
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
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSON(ctx, code, b, v, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalText(code, b, v, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, '[')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = ']'
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '}'
|
||||||
|
return append(b, ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructHead(b []byte) []byte {
|
func appendStructHead(b []byte) []byte {
|
||||||
return append(b, '{')
|
return append(b, '{')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructEnd(b []byte) []byte {
|
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, code.Key...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
return append(b, '}', ',')
|
return append(b, '}', ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructEndSkipLast(b []byte) []byte {
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
last := len(b) - 1
|
last := len(b) - 1
|
||||||
if b[last] == ',' {
|
if b[last] == ',' {
|
||||||
b[last] = '}'
|
b[last] = '}'
|
||||||
return appendComma(b)
|
return appendComma(b)
|
||||||
}
|
}
|
||||||
return appendStructEnd(b)
|
return appendStructEnd(ctx, code, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||||
|
func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,12 +2,41 @@ package vm_debug
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appendInt = encoder.AppendInt
|
||||||
|
appendUint = encoder.AppendUint
|
||||||
|
appendFloat32 = encoder.AppendFloat32
|
||||||
|
appendFloat64 = encoder.AppendFloat64
|
||||||
|
appendString = encoder.AppendString
|
||||||
|
appendByteSlice = encoder.AppendByteSlice
|
||||||
|
appendNumber = encoder.AppendNumber
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
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 errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder (debug): opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
func load(base uintptr, idx uintptr) uintptr {
|
func load(base uintptr, idx uintptr) uintptr {
|
||||||
addr := base + idx
|
addr := base + idx
|
||||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
@ -76,23 +105,111 @@ func appendComma(b []byte) []byte {
|
||||||
return append(b, ',')
|
return append(b, ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
func appendColon(b []byte) []byte {
|
||||||
return append(b, code.Key...)
|
last := len(b) - 1
|
||||||
|
b[last] = ':'
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = append(b, key...)
|
||||||
|
b[len(b)-1] = ':'
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
b[len(b)-1] = '}'
|
||||||
|
b = append(b, ',')
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, _ *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||||
|
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
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSON(ctx, code, b, v, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalText(code, b, v, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, '[')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = ']'
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '}'
|
||||||
|
return append(b, ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructHead(b []byte) []byte {
|
func appendStructHead(b []byte) []byte {
|
||||||
return append(b, '{')
|
return append(b, '{')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructEnd(b []byte) []byte {
|
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, code.Key...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
return append(b, '}', ',')
|
return append(b, '}', ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructEndSkipLast(b []byte) []byte {
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
last := len(b) - 1
|
last := len(b) - 1
|
||||||
if b[last] == ',' {
|
if b[last] == ',' {
|
||||||
b[last] = '}'
|
b[last] = '}'
|
||||||
return appendComma(b)
|
return appendComma(b)
|
||||||
}
|
}
|
||||||
return appendStructEnd(b)
|
return appendStructEnd(ctx, code, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||||
|
func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,9 @@
|
||||||
|
package vm_escaped
|
||||||
|
|
||||||
|
import (
|
||||||
|
// HACK: compile order
|
||||||
|
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` 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 => vm_debug
|
||||||
|
_ "github.com/goccy/go-json/internal/encoder/vm_indent"
|
||||||
|
)
|
|
@ -2,12 +2,41 @@ package vm_escaped
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appendInt = encoder.AppendInt
|
||||||
|
appendUint = encoder.AppendUint
|
||||||
|
appendFloat32 = encoder.AppendFloat32
|
||||||
|
appendFloat64 = encoder.AppendFloat64
|
||||||
|
appendString = encoder.AppendEscapedString
|
||||||
|
appendByteSlice = encoder.AppendByteSlice
|
||||||
|
appendNumber = encoder.AppendNumber
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
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 errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder (escaped): opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
func load(base uintptr, idx uintptr) uintptr {
|
func load(base uintptr, idx uintptr) uintptr {
|
||||||
addr := base + idx
|
addr := base + idx
|
||||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
@ -76,6 +105,89 @@ func appendComma(b []byte) []byte {
|
||||||
return append(b, ',')
|
return append(b, ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendColon(b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = ':'
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = append(b, key...)
|
||||||
|
b[len(b)-1] = ':'
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
b[len(b)-1] = '}'
|
||||||
|
b = append(b, ',')
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, _ *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||||
|
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
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSON(ctx, code, b, v, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalText(code, b, v, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, '[')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = ']'
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '}'
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
func appendStructHead(b []byte) []byte {
|
func appendStructHead(b []byte) []byte {
|
||||||
return append(b, '{')
|
return append(b, '{')
|
||||||
}
|
}
|
||||||
|
@ -84,15 +196,20 @@ func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte)
|
||||||
return append(b, code.EscapedKey...)
|
return append(b, code.EscapedKey...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructEnd(b []byte) []byte {
|
func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
return append(b, '}', ',')
|
return append(b, '}', ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructEndSkipLast(b []byte) []byte {
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
last := len(b) - 1
|
last := len(b) - 1
|
||||||
if b[last] == ',' {
|
if b[last] == ',' {
|
||||||
b[last] = '}'
|
b[last] = '}'
|
||||||
return appendComma(b)
|
return appendComma(b)
|
||||||
}
|
}
|
||||||
return appendStructEnd(b)
|
return appendStructEnd(ctx, code, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||||
|
func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,9 @@
|
||||||
|
package vm_escaped_indent
|
||||||
|
|
||||||
|
import (
|
||||||
|
// HACK: compile order
|
||||||
|
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` 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 => vm_debug
|
||||||
|
_ "github.com/goccy/go-json/internal/encoder/vm_debug"
|
||||||
|
)
|
|
@ -2,12 +2,43 @@ package vm_escaped_indent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appendInt = encoder.AppendInt
|
||||||
|
appendUint = encoder.AppendUint
|
||||||
|
appendFloat32 = encoder.AppendFloat32
|
||||||
|
appendFloat64 = encoder.AppendFloat64
|
||||||
|
appendString = encoder.AppendString
|
||||||
|
appendByteSlice = encoder.AppendByteSlice
|
||||||
|
appendNumber = encoder.AppendNumber
|
||||||
|
appendStructEnd = encoder.AppendStructEndIndent
|
||||||
|
appendIndent = encoder.AppendIndent
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
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 errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder (indent+escaped): opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
func load(base uintptr, idx uintptr) uintptr {
|
func load(base uintptr, idx uintptr) uintptr {
|
||||||
addr := base + idx
|
addr := base + idx
|
||||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
@ -76,6 +107,97 @@ func appendComma(b []byte) []byte {
|
||||||
return append(b, ',', '\n')
|
return append(b, ',', '\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendColon(b []byte) []byte {
|
||||||
|
return append(b, ':', ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, code *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||||
|
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
|
||||||
|
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = appendIndent(ctx, b, code.Indent+1)
|
||||||
|
b = append(b, key...)
|
||||||
|
b[len(b)-2] = ':'
|
||||||
|
b[len(b)-1] = ' '
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = append(b, '[', '\n')
|
||||||
|
return appendIndent(ctx, b, code.Indent+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
return append(b, ']', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '\n'
|
||||||
|
b = appendIndent(ctx, b, code.Indent-1)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSONIndent(ctx, code, b, v, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalTextIndent(code, b, v, true)
|
||||||
|
}
|
||||||
|
|
||||||
func appendStructHead(b []byte) []byte {
|
func appendStructHead(b []byte) []byte {
|
||||||
return append(b, '{', '\n')
|
return append(b, '{', '\n')
|
||||||
}
|
}
|
||||||
|
@ -86,7 +208,7 @@ func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte
|
||||||
return append(b, ' ')
|
return append(b, ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, b []byte, code *encoder.Opcode) []byte {
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
last := len(b) - 1
|
last := len(b) - 1
|
||||||
if b[last-1] == '{' {
|
if b[last-1] == '{' {
|
||||||
b[last] = '}'
|
b[last] = '}'
|
||||||
|
@ -101,3 +223,19 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, b []byte, code *encode
|
||||||
}
|
}
|
||||||
return appendComma(b)
|
return appendComma(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {
|
||||||
|
ctx.BaseIndent = int(load(ctxptr, code.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {
|
||||||
|
store(ctxptr, code.End.Next.Length, indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return appendIndent(ctx, b, code.Indent+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return appendIndent(ctx, b, code.Indent)
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,9 @@
|
||||||
|
package vm_indent
|
||||||
|
|
||||||
|
import (
|
||||||
|
// HACK: compile order
|
||||||
|
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` 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 => vm_debug
|
||||||
|
_ "github.com/goccy/go-json/internal/encoder/vm_escaped_indent"
|
||||||
|
)
|
|
@ -2,12 +2,43 @@ package vm_indent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appendInt = encoder.AppendInt
|
||||||
|
appendUint = encoder.AppendUint
|
||||||
|
appendFloat32 = encoder.AppendFloat32
|
||||||
|
appendFloat64 = encoder.AppendFloat64
|
||||||
|
appendString = encoder.AppendString
|
||||||
|
appendByteSlice = encoder.AppendByteSlice
|
||||||
|
appendNumber = encoder.AppendNumber
|
||||||
|
appendStructEnd = encoder.AppendStructEndIndent
|
||||||
|
appendIndent = encoder.AppendIndent
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
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 errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
func load(base uintptr, idx uintptr) uintptr {
|
func load(base uintptr, idx uintptr) uintptr {
|
||||||
addr := base + idx
|
addr := base + idx
|
||||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
@ -76,6 +107,97 @@ func appendComma(b []byte) []byte {
|
||||||
return append(b, ',', '\n')
|
return append(b, ',', '\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendColon(b []byte) []byte {
|
||||||
|
return append(b, ':', ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, code *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||||
|
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
|
||||||
|
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = appendIndent(ctx, b, code.Indent+1)
|
||||||
|
b = append(b, key...)
|
||||||
|
b[len(b)-2] = ':'
|
||||||
|
b[len(b)-1] = ' '
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = append(b, '[', '\n')
|
||||||
|
return appendIndent(ctx, b, code.Indent+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
return append(b, ']', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '\n'
|
||||||
|
b = appendIndent(ctx, b, code.Indent-1)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSONIndent(ctx, code, b, v, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalTextIndent(code, b, v, false)
|
||||||
|
}
|
||||||
|
|
||||||
func appendStructHead(b []byte) []byte {
|
func appendStructHead(b []byte) []byte {
|
||||||
return append(b, '{', '\n')
|
return append(b, '{', '\n')
|
||||||
}
|
}
|
||||||
|
@ -86,7 +208,7 @@ func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte
|
||||||
return append(b, ' ')
|
return append(b, ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, b []byte, code *encoder.Opcode) []byte {
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
last := len(b) - 1
|
last := len(b) - 1
|
||||||
if b[last-1] == '{' {
|
if b[last-1] == '{' {
|
||||||
b[last] = '}'
|
b[last] = '}'
|
||||||
|
@ -101,3 +223,19 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, b []byte, code *encode
|
||||||
}
|
}
|
||||||
return appendComma(b)
|
return appendComma(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {
|
||||||
|
ctx.BaseIndent = int(load(ctxptr, code.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {
|
||||||
|
store(ctxptr, code.End.Next.Length, indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return appendIndent(ctx, b, code.Indent+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return appendIndent(ctx, b, code.Indent)
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue