Add NilSliceAsEmpty encode option

This commit is contained in:
w1ck3dg0ph3r 2022-09-01 10:42:38 +04:00
parent 41ad89fe02
commit 4cb0c9b28f
No known key found for this signature in database
GPG Key ID: 508376B17E6F5DEB
8 changed files with 93 additions and 11 deletions

View File

@ -426,6 +426,21 @@ func Test_Marshal(t *testing.T) {
assertErr(t, err) assertErr(t, err)
assertEq(t, "[]interface{}", `[1,2.1,"hello"]`, string(bytes)) assertEq(t, "[]interface{}", `[1,2.1,"hello"]`, string(bytes))
}) })
t.Run("nil_slice", func(t *testing.T) {
var a []int
bytes, err := json.Marshal(a)
assertErr(t, err)
assertEq(t, "nil_slice", `null`, string(bytes))
bytes, err = json.Marshal(&a)
assertErr(t, err)
assertEq(t, "nil_slice_ptr", `null`, string(bytes))
bytes, err = json.MarshalWithOption(a, json.NilSliceAsEmpty())
assertErr(t, err)
assertEq(t, "nil_slice_as_empty", `[]`, string(bytes))
bytes, err = json.MarshalWithOption(&a, json.NilSliceAsEmpty())
assertErr(t, err)
assertEq(t, "nil_slice_ptr_as_empty", `[]`, string(bytes))
})
}) })
t.Run("array", func(t *testing.T) { t.Run("array", func(t *testing.T) {
@ -590,6 +605,15 @@ func Test_MarshalIndent(t *testing.T) {
result := "[\n-\t1,\n-\t2.1,\n-\t\"hello\"\n-]" result := "[\n-\t1,\n-\t2.1,\n-\t\"hello\"\n-]"
assertEq(t, "[]interface{}", result, string(bytes)) assertEq(t, "[]interface{}", result, string(bytes))
}) })
t.Run("nil", func(t *testing.T) {
var a []int
bytes, err := json.MarshalIndent(a, prefix, indent)
assertErr(t, err)
assertEq(t, "nil_slice", `null`, string(bytes))
bytes, err = json.MarshalIndentWithOption(a, prefix, indent, json.NilSliceAsEmpty())
assertErr(t, err)
assertEq(t, "nil_slice_as_empty", `[]`, string(bytes))
})
}) })
t.Run("array", func(t *testing.T) { t.Run("array", func(t *testing.T) {

View File

@ -301,19 +301,29 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
b = appendComma(ctx, bb) b = appendComma(ctx, bb)
code = code.Next code = code.Next
case encoder.OpSlicePtr: case encoder.OpSlicePtr:
nilSliceAsEmpty := ctx.Option.Flag & encoder.NilSliceAsEmptyOption != 0
p := loadNPtr(ctxptr, code.Idx, code.PtrNum) p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
if p == 0 { if p == 0 {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }
store(ctxptr, code.Idx, p) store(ctxptr, code.Idx, p)
fallthrough fallthrough
case encoder.OpSlice: case encoder.OpSlice:
nilSliceAsEmpty := ctx.Option.Flag & encoder.NilSliceAsEmptyOption != 0
p := load(ctxptr, code.Idx) p := load(ctxptr, code.Idx)
slice := ptrToSlice(p) slice := ptrToSlice(p)
if p == 0 || slice.Data == nil { if p == 0 || slice.Data == nil {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }

View File

@ -5,12 +5,13 @@ import (
"io" "io"
) )
type OptionFlag uint8 type OptionFlag uint16
const ( const (
HTMLEscapeOption OptionFlag = 1 << iota HTMLEscapeOption OptionFlag = 1 << iota
IndentOption IndentOption
UnorderedMapOption UnorderedMapOption
NilSliceAsEmptyOption
DebugOption DebugOption
ColorizeOption ColorizeOption
ContextOption ContextOption

View File

@ -301,19 +301,29 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
b = appendComma(ctx, bb) b = appendComma(ctx, bb)
code = code.Next code = code.Next
case encoder.OpSlicePtr: case encoder.OpSlicePtr:
nilSliceAsEmpty := ctx.Option.Flag&encoder.NilSliceAsEmptyOption != 0
p := loadNPtr(ctxptr, code.Idx, code.PtrNum) p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
if p == 0 { if p == 0 {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }
store(ctxptr, code.Idx, p) store(ctxptr, code.Idx, p)
fallthrough fallthrough
case encoder.OpSlice: case encoder.OpSlice:
nilSliceAsEmpty := ctx.Option.Flag&encoder.NilSliceAsEmptyOption != 0
p := load(ctxptr, code.Idx) p := load(ctxptr, code.Idx)
slice := ptrToSlice(p) slice := ptrToSlice(p)
if p == 0 || slice.Data == nil { if p == 0 || slice.Data == nil {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }

View File

@ -301,19 +301,29 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
b = appendComma(ctx, bb) b = appendComma(ctx, bb)
code = code.Next code = code.Next
case encoder.OpSlicePtr: case encoder.OpSlicePtr:
nilSliceAsEmpty := ctx.Option.Flag&encoder.NilSliceAsEmptyOption != 0
p := loadNPtr(ctxptr, code.Idx, code.PtrNum) p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
if p == 0 { if p == 0 {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }
store(ctxptr, code.Idx, p) store(ctxptr, code.Idx, p)
fallthrough fallthrough
case encoder.OpSlice: case encoder.OpSlice:
nilSliceAsEmpty := ctx.Option.Flag&encoder.NilSliceAsEmptyOption != 0
p := load(ctxptr, code.Idx) p := load(ctxptr, code.Idx)
slice := ptrToSlice(p) slice := ptrToSlice(p)
if p == 0 || slice.Data == nil { if p == 0 || slice.Data == nil {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }

View File

@ -301,19 +301,29 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
b = appendComma(ctx, bb) b = appendComma(ctx, bb)
code = code.Next code = code.Next
case encoder.OpSlicePtr: case encoder.OpSlicePtr:
nilSliceAsEmpty := ctx.Option.Flag&encoder.NilSliceAsEmptyOption != 0
p := loadNPtr(ctxptr, code.Idx, code.PtrNum) p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
if p == 0 { if p == 0 {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }
store(ctxptr, code.Idx, p) store(ctxptr, code.Idx, p)
fallthrough fallthrough
case encoder.OpSlice: case encoder.OpSlice:
nilSliceAsEmpty := ctx.Option.Flag&encoder.NilSliceAsEmptyOption != 0
p := load(ctxptr, code.Idx) p := load(ctxptr, code.Idx)
slice := ptrToSlice(p) slice := ptrToSlice(p)
if p == 0 || slice.Data == nil { if p == 0 || slice.Data == nil {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }

View File

@ -301,19 +301,29 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
b = appendComma(ctx, bb) b = appendComma(ctx, bb)
code = code.Next code = code.Next
case encoder.OpSlicePtr: case encoder.OpSlicePtr:
nilSliceAsEmpty := ctx.Option.Flag&encoder.NilSliceAsEmptyOption != 0
p := loadNPtr(ctxptr, code.Idx, code.PtrNum) p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
if p == 0 { if p == 0 {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }
store(ctxptr, code.Idx, p) store(ctxptr, code.Idx, p)
fallthrough fallthrough
case encoder.OpSlice: case encoder.OpSlice:
nilSliceAsEmpty := ctx.Option.Flag&encoder.NilSliceAsEmptyOption != 0
p := load(ctxptr, code.Idx) p := load(ctxptr, code.Idx)
slice := ptrToSlice(p) slice := ptrToSlice(p)
if p == 0 || slice.Data == nil { if p == 0 || slice.Data == nil {
b = appendNullComma(ctx, b) if nilSliceAsEmpty {
b = appendEmptyArray(ctx, b)
} else {
b = appendNullComma(ctx, b)
}
code = code.End.Next code = code.End.Next
break break
} }

View File

@ -17,6 +17,13 @@ func UnorderedMap() EncodeOptionFunc {
} }
} }
// NilSliceAsEmpty encodes nil slices as [] instead of null.
func NilSliceAsEmpty() EncodeOptionFunc {
return func(opt *EncodeOption) {
opt.Flag |= encoder.NilSliceAsEmptyOption
}
}
// DisableHTMLEscape disables escaping of HTML characters ( '&', '<', '>' ) when encoding string. // DisableHTMLEscape disables escaping of HTML characters ( '&', '<', '>' ) when encoding string.
func DisableHTMLEscape() EncodeOptionFunc { func DisableHTMLEscape() EncodeOptionFunc {
return func(opt *EncodeOption) { return func(opt *EncodeOption) {