forked from mirror/go-json
Merge pull request #231 from goccy/feature/refactor-encode-opt
Refactor encode option
This commit is contained in:
commit
8c93c749f9
112
encode.go
112
encode.go
|
@ -20,15 +20,6 @@ type Encoder struct {
|
|||
indentStr string
|
||||
}
|
||||
|
||||
type EncodeOption int
|
||||
|
||||
const (
|
||||
EncodeOptionHTMLEscape EncodeOption = 1 << iota
|
||||
EncodeOptionIndent
|
||||
EncodeOptionUnorderedMap
|
||||
EncodeOptionDebug
|
||||
)
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{w: w, enabledHTMLEscape: true}
|
||||
|
@ -52,21 +43,21 @@ func (e *Encoder) EncodeWithOption(v interface{}, optFuncs ...EncodeOptionFunc)
|
|||
}
|
||||
|
||||
func (e *Encoder) encodeWithOption(ctx *encoder.RuntimeContext, v interface{}, optFuncs ...EncodeOptionFunc) error {
|
||||
var opt EncodeOption
|
||||
initOption(ctx.Option)
|
||||
if e.enabledHTMLEscape {
|
||||
opt |= EncodeOptionHTMLEscape
|
||||
ctx.Option.HTMLEscape = true
|
||||
}
|
||||
for _, optFunc := range optFuncs {
|
||||
opt = optFunc(opt)
|
||||
optFunc(ctx.Option)
|
||||
}
|
||||
var (
|
||||
buf []byte
|
||||
err error
|
||||
)
|
||||
if e.enabledIndent {
|
||||
buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr, opt)
|
||||
buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr)
|
||||
} else {
|
||||
buf, err = encode(ctx, v, opt)
|
||||
buf, err = encode(ctx, v)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -103,10 +94,16 @@ func (e *Encoder) SetIndent(prefix, indent string) {
|
|||
e.enabledIndent = true
|
||||
}
|
||||
|
||||
func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
|
||||
func marshal(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||
ctx := encoder.TakeRuntimeContext()
|
||||
|
||||
buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape)
|
||||
initOption(ctx.Option)
|
||||
ctx.Option.HTMLEscape = true
|
||||
for _, optFunc := range optFuncs {
|
||||
optFunc(ctx.Option)
|
||||
}
|
||||
|
||||
buf, err := encode(ctx, v)
|
||||
if err != nil {
|
||||
encoder.ReleaseRuntimeContext(ctx)
|
||||
return nil, err
|
||||
|
@ -124,10 +121,13 @@ func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
|
|||
return copied, nil
|
||||
}
|
||||
|
||||
func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
|
||||
func marshalNoEscape(v interface{}) ([]byte, error) {
|
||||
ctx := encoder.TakeRuntimeContext()
|
||||
|
||||
buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape)
|
||||
initOption(ctx.Option)
|
||||
ctx.Option.HTMLEscape = true
|
||||
|
||||
buf, err := encodeNoEscape(ctx, v)
|
||||
if err != nil {
|
||||
encoder.ReleaseRuntimeContext(ctx)
|
||||
return nil, err
|
||||
|
@ -145,10 +145,17 @@ func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
|
|||
return copied, nil
|
||||
}
|
||||
|
||||
func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]byte, error) {
|
||||
func marshalIndent(v interface{}, prefix, indent string, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||
ctx := encoder.TakeRuntimeContext()
|
||||
|
||||
buf, err := encodeIndent(ctx, v, prefix, indent, opt|EncodeOptionHTMLEscape)
|
||||
initOption(ctx.Option)
|
||||
ctx.Option.HTMLEscape = true
|
||||
ctx.Option.Indent = true
|
||||
for _, optFunc := range optFuncs {
|
||||
optFunc(ctx.Option)
|
||||
}
|
||||
|
||||
buf, err := encodeIndent(ctx, v, prefix, indent)
|
||||
if err != nil {
|
||||
encoder.ReleaseRuntimeContext(ctx)
|
||||
return nil, err
|
||||
|
@ -162,7 +169,7 @@ func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]by
|
|||
return copied, nil
|
||||
}
|
||||
|
||||
func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
|
||||
func encode(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) {
|
||||
b := ctx.Buf[:0]
|
||||
if v == nil {
|
||||
b = encoder.AppendNull(b)
|
||||
|
@ -180,7 +187,7 @@ func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byt
|
|||
|
||||
p := uintptr(header.ptr)
|
||||
var code *encoder.Opcode
|
||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||
if ctx.Option.HTMLEscape {
|
||||
code = codeSet.EscapeKeyCode
|
||||
} else {
|
||||
code = codeSet.NoescapeKeyCode
|
||||
|
@ -188,7 +195,7 @@ func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byt
|
|||
ctx.Init(code, p, codeSet.CodeLength)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, header.ptr)
|
||||
|
||||
buf, err := encodeRunCode(ctx, b, codeSet, opt)
|
||||
buf, err := encodeRunCode(ctx, b, codeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -196,7 +203,7 @@ func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byt
|
|||
return buf, nil
|
||||
}
|
||||
|
||||
func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
|
||||
func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) {
|
||||
b := ctx.Buf[:0]
|
||||
if v == nil {
|
||||
b = encoder.AppendNull(b)
|
||||
|
@ -213,14 +220,14 @@ func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption
|
|||
}
|
||||
|
||||
var code *encoder.Opcode
|
||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||
if ctx.Option.HTMLEscape {
|
||||
code = codeSet.EscapeKeyCode
|
||||
} else {
|
||||
code = codeSet.NoescapeKeyCode
|
||||
}
|
||||
p := uintptr(header.ptr)
|
||||
ctx.Init(code, p, codeSet.CodeLength)
|
||||
buf, err := encodeRunCode(ctx, b, codeSet, opt)
|
||||
buf, err := encodeRunCode(ctx, b, codeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -229,7 +236,7 @@ func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption
|
|||
return buf, nil
|
||||
}
|
||||
|
||||
func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent string, opt EncodeOption) ([]byte, error) {
|
||||
func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent string) ([]byte, error) {
|
||||
b := ctx.Buf[:0]
|
||||
if v == nil {
|
||||
b = encoder.AppendNull(b)
|
||||
|
@ -246,14 +253,14 @@ func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent str
|
|||
}
|
||||
|
||||
var code *encoder.Opcode
|
||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||
if ctx.Option.HTMLEscape {
|
||||
code = codeSet.EscapeKeyCode
|
||||
} else {
|
||||
code = codeSet.NoescapeKeyCode
|
||||
}
|
||||
p := uintptr(header.ptr)
|
||||
ctx.Init(code, p, codeSet.CodeLength)
|
||||
buf, err := encodeRunIndentCode(ctx, b, codeSet, prefix, indent, opt)
|
||||
buf, err := encodeRunIndentCode(ctx, b, codeSet, prefix, indent)
|
||||
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, header.ptr)
|
||||
|
||||
|
@ -265,38 +272,45 @@ func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent str
|
|||
return buf, nil
|
||||
}
|
||||
|
||||
func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) {
|
||||
if (opt & EncodeOptionDebug) != 0 {
|
||||
return encodeDebugRunCode(ctx, b, codeSet, opt)
|
||||
func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
if ctx.Option.Debug {
|
||||
return encodeDebugRunCode(ctx, b, codeSet)
|
||||
}
|
||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||
return vm_escaped.Run(ctx, b, codeSet, encoder.Option(opt))
|
||||
if ctx.Option.HTMLEscape {
|
||||
return vm_escaped.Run(ctx, b, codeSet)
|
||||
}
|
||||
return vm.Run(ctx, b, codeSet, encoder.Option(opt))
|
||||
return vm.Run(ctx, b, codeSet)
|
||||
}
|
||||
|
||||
func encodeDebugRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) {
|
||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||
return vm_escaped.DebugRun(ctx, b, codeSet, encoder.Option(opt))
|
||||
func encodeDebugRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
if ctx.Option.HTMLEscape {
|
||||
return vm_escaped.DebugRun(ctx, b, codeSet)
|
||||
}
|
||||
return vm.DebugRun(ctx, b, codeSet, encoder.Option(opt))
|
||||
return vm.DebugRun(ctx, b, codeSet)
|
||||
}
|
||||
|
||||
func encodeRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, prefix, indent string, opt EncodeOption) ([]byte, error) {
|
||||
func encodeRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, prefix, indent string) ([]byte, error) {
|
||||
ctx.Prefix = []byte(prefix)
|
||||
ctx.IndentStr = []byte(indent)
|
||||
if (opt & EncodeOptionDebug) != 0 {
|
||||
return encodeDebugRunIndentCode(ctx, b, codeSet, opt)
|
||||
if ctx.Option.Debug {
|
||||
return encodeDebugRunIndentCode(ctx, b, codeSet)
|
||||
}
|
||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||
return vm_escaped_indent.Run(ctx, b, codeSet, encoder.Option(opt))
|
||||
if ctx.Option.HTMLEscape {
|
||||
return vm_escaped_indent.Run(ctx, b, codeSet)
|
||||
}
|
||||
return vm_indent.Run(ctx, b, codeSet, encoder.Option(opt))
|
||||
return vm_indent.Run(ctx, b, codeSet)
|
||||
}
|
||||
|
||||
func encodeDebugRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) {
|
||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||
return vm_escaped_indent.DebugRun(ctx, b, codeSet, encoder.Option(opt))
|
||||
func encodeDebugRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
if ctx.Option.HTMLEscape {
|
||||
return vm_escaped_indent.DebugRun(ctx, b, codeSet)
|
||||
}
|
||||
return vm_indent.DebugRun(ctx, b, codeSet, encoder.Option(opt))
|
||||
return vm_indent.DebugRun(ctx, b, codeSet)
|
||||
}
|
||||
|
||||
func initOption(opt *EncodeOption) {
|
||||
opt.HTMLEscape = false
|
||||
opt.Indent = false
|
||||
opt.UnorderedMap = false
|
||||
opt.Debug = false
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
ctxptr := ctx.Ptr()
|
||||
|
@ -185,7 +185,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
bb, err := appendInterface(ctx, codeSet, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -365,13 +365,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
if (opt & encoder.UnorderedMapOption) == 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
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 = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -380,7 +380,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
if idx < length {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
|
@ -409,7 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
|
|
|
@ -97,6 +97,7 @@ var (
|
|||
Buf: make([]byte, 0, bufSize),
|
||||
Ptrs: make([]uintptr, 128),
|
||||
KeepRefs: make([]unsafe.Pointer, 0, 8),
|
||||
Option: &Option{},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -112,6 +113,7 @@ type RuntimeContext struct {
|
|||
Prefix []byte
|
||||
IndentStr []byte
|
||||
Code *Opcode
|
||||
Option *Option
|
||||
}
|
||||
|
||||
func (c *RuntimeContext) Init(code *Opcode, p uintptr, codelen int) {
|
||||
|
|
|
@ -17,14 +17,6 @@ import (
|
|||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
type Option int
|
||||
|
||||
const (
|
||||
HTMLEscapeOption Option = 1 << iota
|
||||
IndentOption
|
||||
UnorderedMapOption
|
||||
)
|
||||
|
||||
func (t OpType) IsMultipleOpHead() bool {
|
||||
switch t {
|
||||
case OpStructHead:
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package encoder
|
||||
|
||||
type Option struct {
|
||||
HTMLEscape bool
|
||||
Indent bool
|
||||
UnorderedMap bool
|
||||
Debug bool
|
||||
}
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("=============[DEBUG]===============")
|
||||
|
@ -23,5 +23,5 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet,
|
|||
}
|
||||
}()
|
||||
|
||||
return Run(ctx, b, codeSet, opt)
|
||||
return Run(ctx, b, codeSet)
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte
|
|||
return b
|
||||
}
|
||||
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, _ *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, _ *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 {
|
||||
|
@ -148,7 +148,7 @@ func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, op
|
|||
ctx.Ptrs = newPtrs
|
||||
ctx.Code = ifaceCodeSet.NoescapeKeyCode
|
||||
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
bb, err := Run(ctx, b, ifaceCodeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
ctxptr := ctx.Ptr()
|
||||
|
@ -185,7 +185,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
bb, err := appendInterface(ctx, codeSet, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -365,13 +365,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
if (opt & encoder.UnorderedMapOption) == 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
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 = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -380,7 +380,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
if idx < length {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
|
@ -409,7 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("=============[DEBUG]===============")
|
||||
|
@ -23,5 +23,5 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet,
|
|||
}
|
||||
}()
|
||||
|
||||
return Run(ctx, b, codeSet, opt)
|
||||
return Run(ctx, b, codeSet)
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte
|
|||
return b
|
||||
}
|
||||
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, _ *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, _ *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 {
|
||||
|
@ -148,7 +148,7 @@ func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, op
|
|||
ctx.Ptrs = newPtrs
|
||||
ctx.Code = ifaceCodeSet.EscapeKeyCode
|
||||
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
bb, err := Run(ctx, b, ifaceCodeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
ctxptr := ctx.Ptr()
|
||||
|
@ -185,7 +185,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
bb, err := appendInterface(ctx, codeSet, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -365,13 +365,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
if (opt & encoder.UnorderedMapOption) == 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
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 = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -380,7 +380,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
if idx < length {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
|
@ -409,7 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("=============[DEBUG]===============")
|
||||
|
@ -23,5 +23,5 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet,
|
|||
}
|
||||
}()
|
||||
|
||||
return Run(ctx, b, codeSet, opt)
|
||||
return Run(ctx, b, codeSet)
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ 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) {
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, 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 {
|
||||
|
@ -138,7 +138,7 @@ func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, op
|
|||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent = code.Indent
|
||||
ctx.Code = ifaceCodeSet.EscapeKeyCode
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
bb, err := Run(ctx, b, ifaceCodeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
ctxptr := ctx.Ptr()
|
||||
|
@ -185,7 +185,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
bb, err := appendInterface(ctx, codeSet, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -365,13 +365,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
if (opt & encoder.UnorderedMapOption) == 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
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 = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -380,7 +380,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
if idx < length {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
|
@ -409,7 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("=============[DEBUG]===============")
|
||||
|
@ -23,5 +23,5 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet,
|
|||
}
|
||||
}()
|
||||
|
||||
return Run(ctx, b, codeSet, opt)
|
||||
return Run(ctx, b, codeSet)
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ 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) {
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, 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 {
|
||||
|
@ -138,7 +138,7 @@ func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, op
|
|||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent = code.Indent
|
||||
ctx.Code = ifaceCodeSet.NoescapeKeyCode
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
bb, err := Run(ctx, b, ifaceCodeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
ctxptr := ctx.Ptr()
|
||||
|
@ -185,7 +185,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
bb, err := appendInterface(ctx, codeSet, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -365,13 +365,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.ElemIdx, 0)
|
||||
store(ctxptr, code.Length, uintptr(mlen))
|
||||
store(ctxptr, code.MapIter, uintptr(iter))
|
||||
if (opt & encoder.UnorderedMapOption) == 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
} else {
|
||||
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 = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -380,7 +380,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx := load(ctxptr, code.ElemIdx)
|
||||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
if idx < length {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
|
@ -409,7 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if ctx.Option.UnorderedMap {
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
|
|
16
json.go
16
json.go
|
@ -160,16 +160,12 @@ func Marshal(v interface{}) ([]byte, error) {
|
|||
|
||||
// MarshalNoEscape
|
||||
func MarshalNoEscape(v interface{}) ([]byte, error) {
|
||||
return marshalNoEscape(v, EncodeOptionHTMLEscape)
|
||||
return marshalNoEscape(v)
|
||||
}
|
||||
|
||||
// MarshalWithOption returns the JSON encoding of v with EncodeOption.
|
||||
func MarshalWithOption(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||
opt := EncodeOptionHTMLEscape
|
||||
for _, optFunc := range optFuncs {
|
||||
opt = optFunc(opt)
|
||||
}
|
||||
return marshal(v, opt)
|
||||
return marshal(v, optFuncs...)
|
||||
}
|
||||
|
||||
// MarshalIndent is like Marshal but applies Indent to format the output.
|
||||
|
@ -181,11 +177,7 @@ func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
|
|||
|
||||
// MarshalIndentWithOption is like Marshal but applies Indent to format the output with EncodeOption.
|
||||
func MarshalIndentWithOption(v interface{}, prefix, indent string, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||
opt := EncodeOptionHTMLEscape | EncodeOptionIndent
|
||||
for _, optFunc := range optFuncs {
|
||||
opt = optFunc(opt)
|
||||
}
|
||||
return marshalIndent(v, prefix, indent, opt)
|
||||
return marshalIndent(v, prefix, indent, optFuncs...)
|
||||
}
|
||||
|
||||
// Unmarshal parses the JSON-encoded data and stores the result
|
||||
|
@ -326,7 +318,7 @@ func HTMLEscape(dst *bytes.Buffer, src []byte) {
|
|||
if err := dec.Decode(&v); err != nil {
|
||||
return
|
||||
}
|
||||
buf, _ := marshal(v, EncodeOptionHTMLEscape)
|
||||
buf, _ := marshal(v)
|
||||
dst.Write(buf)
|
||||
}
|
||||
|
||||
|
|
20
option.go
20
option.go
|
@ -1,15 +1,21 @@
|
|||
package json
|
||||
|
||||
type EncodeOptionFunc func(EncodeOption) EncodeOption
|
||||
import (
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
func UnorderedMap() func(EncodeOption) EncodeOption {
|
||||
return func(opt EncodeOption) EncodeOption {
|
||||
return opt | EncodeOptionUnorderedMap
|
||||
type EncodeOption = encoder.Option
|
||||
|
||||
type EncodeOptionFunc func(*EncodeOption)
|
||||
|
||||
func UnorderedMap() EncodeOptionFunc {
|
||||
return func(opt *EncodeOption) {
|
||||
opt.UnorderedMap = true
|
||||
}
|
||||
}
|
||||
|
||||
func Debug() func(EncodeOption) EncodeOption {
|
||||
return func(opt EncodeOption) EncodeOption {
|
||||
return opt | EncodeOptionDebug
|
||||
func Debug() EncodeOptionFunc {
|
||||
return func(opt *EncodeOption) {
|
||||
opt.Debug = true
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue