Support omitempty

This commit is contained in:
Masaaki Goshima 2020-05-01 13:12:01 +09:00
parent e50e1d4878
commit 03a21193fc
5 changed files with 943 additions and 73 deletions

View File

@ -23,14 +23,14 @@ type opcodeMap struct {
sync.Map
}
func (m *opcodeMap) Get(k string) *opcode {
func (m *opcodeMap) Get(k *rtype) *opcode {
if v, ok := m.Load(k); ok {
return v.(*opcode)
}
return nil
}
func (m *opcodeMap) Set(k string, op *opcode) {
func (m *opcodeMap) Set(k *rtype, op *opcode) {
m.Store(k, op)
}
@ -175,8 +175,7 @@ func (e *Encoder) encode(v interface{}) error {
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
name := typ.String()
if code := cachedOpcode.Get(name); code != nil {
if code := cachedOpcode.Get(typ); code != nil {
p := uintptr(header.ptr)
code.ptr = p
if err := e.run(code); err != nil {
@ -188,9 +187,7 @@ func (e *Encoder) encode(v interface{}) error {
if err != nil {
return err
}
if name != "" {
cachedOpcode.Set(name, code)
}
cachedOpcode.Set(typ, code)
p := uintptr(header.ptr)
code.ptr = p
return e.run(code)

View File

@ -89,6 +89,36 @@ func (e *Encoder) optimizeStructFieldPtrHead(typ *rtype, code *opcode) *opcode {
code.op = opStructFieldPtrHeadString
case opStructFieldHeadBool:
code.op = opStructFieldPtrHeadBool
case opStructFieldHeadOmitEmpty:
code.op = opStructFieldPtrHeadOmitEmpty
case opStructFieldHeadIntOmitEmpty:
code.op = opStructFieldPtrHeadIntOmitEmpty
case opStructFieldHeadInt8OmitEmpty:
code.op = opStructFieldPtrHeadInt8OmitEmpty
case opStructFieldHeadInt16OmitEmpty:
code.op = opStructFieldPtrHeadInt16OmitEmpty
case opStructFieldHeadInt32OmitEmpty:
code.op = opStructFieldPtrHeadInt32OmitEmpty
case opStructFieldHeadInt64OmitEmpty:
code.op = opStructFieldPtrHeadInt64OmitEmpty
case opStructFieldHeadUintOmitEmpty:
code.op = opStructFieldPtrHeadUintOmitEmpty
case opStructFieldHeadUint8OmitEmpty:
code.op = opStructFieldPtrHeadUint8OmitEmpty
case opStructFieldHeadUint16OmitEmpty:
code.op = opStructFieldPtrHeadUint16OmitEmpty
case opStructFieldHeadUint32OmitEmpty:
code.op = opStructFieldPtrHeadUint32OmitEmpty
case opStructFieldHeadUint64OmitEmpty:
code.op = opStructFieldPtrHeadUint64OmitEmpty
case opStructFieldHeadFloat32OmitEmpty:
code.op = opStructFieldPtrHeadFloat32OmitEmpty
case opStructFieldHeadFloat64OmitEmpty:
code.op = opStructFieldPtrHeadFloat64OmitEmpty
case opStructFieldHeadStringOmitEmpty:
code.op = opStructFieldPtrHeadStringOmitEmpty
case opStructFieldHeadBoolOmitEmpty:
code.op = opStructFieldPtrHeadBoolOmitEmpty
default:
return newOpCode(opPtr, typ, code)
}
@ -308,6 +338,10 @@ func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
keyName = opts[0]
}
}
isOmitEmpty := false
if len(opts) > 1 {
isOmitEmpty = opts[1] == "omitempty"
}
fieldType := type2rtype(field.Type)
valueCode, err := e.compile(fieldType)
if err != nil {
@ -323,10 +357,45 @@ func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
offset: field.Offset,
}
if fieldIdx == 0 {
fieldCode.op = opStructFieldHead
head = fieldCode
code = (*opcode)(unsafe.Pointer(fieldCode))
prevField = fieldCode
if isOmitEmpty {
fieldCode.op = opStructFieldHeadOmitEmpty
switch valueCode.op {
case opInt:
fieldCode.op = opStructFieldHeadIntOmitEmpty
case opInt8:
fieldCode.op = opStructFieldHeadInt8OmitEmpty
case opInt16:
fieldCode.op = opStructFieldHeadInt16OmitEmpty
case opInt32:
fieldCode.op = opStructFieldHeadInt32OmitEmpty
case opInt64:
fieldCode.op = opStructFieldHeadInt64OmitEmpty
case opUint:
fieldCode.op = opStructFieldHeadUintOmitEmpty
case opUint8:
fieldCode.op = opStructFieldHeadUint8OmitEmpty
case opUint16:
fieldCode.op = opStructFieldHeadUint16OmitEmpty
case opUint32:
fieldCode.op = opStructFieldHeadUint32OmitEmpty
case opUint64:
fieldCode.op = opStructFieldHeadUint64OmitEmpty
case opFloat32:
fieldCode.op = opStructFieldHeadFloat32OmitEmpty
case opFloat64:
fieldCode.op = opStructFieldHeadFloat64OmitEmpty
case opString:
fieldCode.op = opStructFieldHeadStringOmitEmpty
case opBool:
fieldCode.op = opStructFieldHeadBoolOmitEmpty
default:
code = valueCode.beforeLastCode()
}
} else {
fieldCode.op = opStructFieldHead
switch valueCode.op {
case opInt:
fieldCode.op = opStructFieldHeadInt
@ -359,12 +428,48 @@ func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
default:
code = valueCode.beforeLastCode()
}
}
} else {
fieldCode.op = opStructField
code.next = (*opcode)(unsafe.Pointer(fieldCode))
prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode))
prevField = fieldCode
code = (*opcode)(unsafe.Pointer(fieldCode))
if isOmitEmpty {
fieldCode.op = opStructFieldOmitEmpty
switch valueCode.op {
case opInt:
fieldCode.op = opStructFieldIntOmitEmpty
case opInt8:
fieldCode.op = opStructFieldInt8OmitEmpty
case opInt16:
fieldCode.op = opStructFieldInt16OmitEmpty
case opInt32:
fieldCode.op = opStructFieldInt32OmitEmpty
case opInt64:
fieldCode.op = opStructFieldInt64OmitEmpty
case opUint:
fieldCode.op = opStructFieldUintOmitEmpty
case opUint8:
fieldCode.op = opStructFieldUint8OmitEmpty
case opUint16:
fieldCode.op = opStructFieldUint16OmitEmpty
case opUint32:
fieldCode.op = opStructFieldUint32OmitEmpty
case opUint64:
fieldCode.op = opStructFieldUint64OmitEmpty
case opFloat32:
fieldCode.op = opStructFieldFloat32OmitEmpty
case opFloat64:
fieldCode.op = opStructFieldFloat64OmitEmpty
case opString:
fieldCode.op = opStructFieldStringOmitEmpty
case opBool:
fieldCode.op = opStructFieldBoolOmitEmpty
default:
code = valueCode.beforeLastCode()
}
} else {
switch valueCode.op {
case opInt:
fieldCode.op = opStructFieldInt
@ -398,10 +503,27 @@ func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
code = valueCode.beforeLastCode()
}
}
prevField.nextField = newEndOp()
}
fieldIdx++
}
structEndCode := newOpCode(opStructEnd, nil, nil)
if prevField != nil && prevField.nextField == nil {
prevField.nextField = structEndCode
}
// no struct field
if head == nil {
head = &structFieldCode{
opcodeHeader: &opcodeHeader{
op: opStructFieldHead,
typ: typ,
},
nextField: structEndCode,
}
code = (*opcode)(unsafe.Pointer(head))
}
head.end = structEndCode
code.next = structEndCode
structEndCode.next = newEndOp()

View File

@ -37,6 +37,8 @@ const (
opMapKey
opMapValue
opMapEnd
// StructFieldHead
opStructFieldHead
opStructFieldHeadInt
opStructFieldHeadInt8
@ -52,6 +54,25 @@ const (
opStructFieldHeadFloat64
opStructFieldHeadString
opStructFieldHeadBool
// StructFieldHead with omitempty
opStructFieldHeadOmitEmpty
opStructFieldHeadIntOmitEmpty
opStructFieldHeadInt8OmitEmpty
opStructFieldHeadInt16OmitEmpty
opStructFieldHeadInt32OmitEmpty
opStructFieldHeadInt64OmitEmpty
opStructFieldHeadUintOmitEmpty
opStructFieldHeadUint8OmitEmpty
opStructFieldHeadUint16OmitEmpty
opStructFieldHeadUint32OmitEmpty
opStructFieldHeadUint64OmitEmpty
opStructFieldHeadFloat32OmitEmpty
opStructFieldHeadFloat64OmitEmpty
opStructFieldHeadStringOmitEmpty
opStructFieldHeadBoolOmitEmpty
// StructFieldHead for pointer structure
opStructFieldPtrHead
opStructFieldPtrHeadInt
opStructFieldPtrHeadInt8
@ -67,6 +88,25 @@ const (
opStructFieldPtrHeadFloat64
opStructFieldPtrHeadString
opStructFieldPtrHeadBool
// StructFieldPtrHead with omitempty
opStructFieldPtrHeadOmitEmpty
opStructFieldPtrHeadIntOmitEmpty
opStructFieldPtrHeadInt8OmitEmpty
opStructFieldPtrHeadInt16OmitEmpty
opStructFieldPtrHeadInt32OmitEmpty
opStructFieldPtrHeadInt64OmitEmpty
opStructFieldPtrHeadUintOmitEmpty
opStructFieldPtrHeadUint8OmitEmpty
opStructFieldPtrHeadUint16OmitEmpty
opStructFieldPtrHeadUint32OmitEmpty
opStructFieldPtrHeadUint64OmitEmpty
opStructFieldPtrHeadFloat32OmitEmpty
opStructFieldPtrHeadFloat64OmitEmpty
opStructFieldPtrHeadStringOmitEmpty
opStructFieldPtrHeadBoolOmitEmpty
// StructField
opStructField
opStructFieldInt
opStructFieldInt8
@ -82,6 +122,24 @@ const (
opStructFieldFloat64
opStructFieldString
opStructFieldBool
// StructField with omitempty
opStructFieldOmitEmpty
opStructFieldIntOmitEmpty
opStructFieldInt8OmitEmpty
opStructFieldInt16OmitEmpty
opStructFieldInt32OmitEmpty
opStructFieldInt64OmitEmpty
opStructFieldUintOmitEmpty
opStructFieldUint8OmitEmpty
opStructFieldUint16OmitEmpty
opStructFieldUint32OmitEmpty
opStructFieldUint64OmitEmpty
opStructFieldFloat32OmitEmpty
opStructFieldFloat64OmitEmpty
opStructFieldStringOmitEmpty
opStructFieldBoolOmitEmpty
opStructEnd
)
@ -141,6 +199,7 @@ func (t opType) String() string {
return "MAP_VALUE"
case opMapEnd:
return "MAP_END"
case opStructFieldHead:
return "STRUCT_FIELD_HEAD"
case opStructFieldHeadInt:
@ -171,6 +230,38 @@ func (t opType) String() string {
return "STRUCT_FIELD_HEAD_STRING"
case opStructFieldHeadBool:
return "STRUCT_FIELD_HEAD_BOOL"
case opStructFieldHeadOmitEmpty:
return "STRUCT_FIELD_HEAD_OMIT_EMPTY"
case opStructFieldHeadIntOmitEmpty:
return "STRUCT_FIELD_HEAD_INT_OMIT_EMPTY"
case opStructFieldHeadInt8OmitEmpty:
return "STRUCT_FIELD_HEAD_INT8_OMIT_EMPTY"
case opStructFieldHeadInt16OmitEmpty:
return "STRUCT_FIELD_HEAD_INT16_OMIT_EMPTY"
case opStructFieldHeadInt32OmitEmpty:
return "STRUCT_FIELD_HEAD_INT32_OMIT_EMPTY"
case opStructFieldHeadInt64OmitEmpty:
return "STRUCT_FIELD_HEAD_INT64_OMIT_EMPTY"
case opStructFieldHeadUintOmitEmpty:
return "STRUCT_FIELD_HEAD_UINT_OMIT_EMPTY"
case opStructFieldHeadUint8OmitEmpty:
return "STRUCT_FIELD_HEAD_UINT8_OMIT_EMPTY"
case opStructFieldHeadUint16OmitEmpty:
return "STRUCT_FIELD_HEAD_UINT16_OMIT_EMPTY"
case opStructFieldHeadUint32OmitEmpty:
return "STRUCT_FIELD_HEAD_UINT32_OMIT_EMPTY"
case opStructFieldHeadUint64OmitEmpty:
return "STRUCT_FIELD_HEAD_UINT64_OMIT_EMPTY"
case opStructFieldHeadFloat32OmitEmpty:
return "STRUCT_FIELD_HEAD_FLOAT32_OMIT_EMPTY"
case opStructFieldHeadFloat64OmitEmpty:
return "STRUCT_FIELD_HEAD_FLOAT64_OMIT_EMPTY"
case opStructFieldHeadStringOmitEmpty:
return "STRUCT_FIELD_HEAD_STRING_OMIT_EMPTY"
case opStructFieldHeadBoolOmitEmpty:
return "STRUCT_FIELD_HEAD_BOOL_OMIT_EMPTY"
case opStructFieldPtrHead:
return "STRUCT_FIELD_PTR_HEAD"
case opStructFieldPtrHeadInt:
@ -201,6 +292,38 @@ func (t opType) String() string {
return "STRUCT_FIELD_PTR_HEAD_STRING"
case opStructFieldPtrHeadBool:
return "STRUCT_FIELD_PTR_HEAD_BOOL"
case opStructFieldPtrHeadOmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_OMIT_EMPTY"
case opStructFieldPtrHeadIntOmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_INT_OMIT_EMPTY"
case opStructFieldPtrHeadInt8OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_INT8_OMIT_EMPTY"
case opStructFieldPtrHeadInt16OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_INT16_OMIT_EMPTY"
case opStructFieldPtrHeadInt32OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_INT32_OMIT_EMPTY"
case opStructFieldPtrHeadInt64OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_INT64_OMIT_EMPTY"
case opStructFieldPtrHeadUintOmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_UINT_OMIT_EMPTY"
case opStructFieldPtrHeadUint8OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_UINT8_OMIT_EMPTY"
case opStructFieldPtrHeadUint16OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_UINT16_OMIT_EMPTY"
case opStructFieldPtrHeadUint32OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_UINT32_OMIT_EMPTY"
case opStructFieldPtrHeadUint64OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_UINT64_OMIT_EMPTY"
case opStructFieldPtrHeadFloat32OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_FLOAT32_OMIT_EMPTY"
case opStructFieldPtrHeadFloat64OmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_FLOAT64_OMIT_EMPTY"
case opStructFieldPtrHeadStringOmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_STRING_OMIT_EMPTY"
case opStructFieldPtrHeadBoolOmitEmpty:
return "STRUCT_FIELD_PTR_HEAD_BOOL_OMIT_EMPTY"
case opStructField:
return "STRUCT_FIELD"
case opStructFieldInt:
@ -231,6 +354,38 @@ func (t opType) String() string {
return "STRUCT_FIELD_STRING"
case opStructFieldBool:
return "STRUCT_FIELD_BOOL"
case opStructFieldOmitEmpty:
return "STRUCT_FIELD_OMIT_EMPTY"
case opStructFieldIntOmitEmpty:
return "STRUCT_FIELD_INT_OMIT_EMPTY"
case opStructFieldInt8OmitEmpty:
return "STRUCT_FIELD_INT8_OMIT_EMPTY"
case opStructFieldInt16OmitEmpty:
return "STRUCT_FIELD_INT16_OMIT_EMPTY"
case opStructFieldInt32OmitEmpty:
return "STRUCT_FIELD_INT32_OMIT_EMPTY"
case opStructFieldInt64OmitEmpty:
return "STRUCT_FIELD_INT64_OMIT_EMPTY"
case opStructFieldUintOmitEmpty:
return "STRUCT_FIELD_UINT_OMIT_EMPTY"
case opStructFieldUint8OmitEmpty:
return "STRUCT_FIELD_UINT8_OMIT_EMPTY"
case opStructFieldUint16OmitEmpty:
return "STRUCT_FIELD_UINT16_OMIT_EMPTY"
case opStructFieldUint32OmitEmpty:
return "STRUCT_FIELD_UINT32_OMIT_EMPTY"
case opStructFieldUint64OmitEmpty:
return "STRUCT_FIELD_UINT64_OMIT_EMPTY"
case opStructFieldFloat32OmitEmpty:
return "STRUCT_FIELD_FLOAT32_OMIT_EMPTY"
case opStructFieldFloat64OmitEmpty:
return "STRUCT_FIELD_FLOAT64_OMIT_EMPTY"
case opStructFieldStringOmitEmpty:
return "STRUCT_FIELD_STRING_OMIT_EMPTY"
case opStructFieldBoolOmitEmpty:
return "STRUCT_FIELD_BOOL_OMIT_EMPTY"
case opStructEnd:
return "STRUCT_END"
}

View File

@ -91,6 +91,72 @@ func Test_Encoder(t *testing.T) {
})
assertErr(t, err)
assertEq(t, "struct", `{"a":-1,"b":1,"c":"hello world"}`, string(bytes))
t.Run("null", func(t *testing.T) {
type T struct {
A *struct{} `json:"a"`
}
var v T
bytes, err := json.Marshal(&v)
assertErr(t, err)
assertEq(t, "struct", `{"a":null}`, string(bytes))
})
t.Run("omitempty", func(t *testing.T) {
type T struct {
A int `json:",omitempty"`
B int8 `json:",omitempty"`
C int16 `json:",omitempty"`
D int32 `json:",omitempty"`
E int64 `json:",omitempty"`
F uint `json:",omitempty"`
G uint8 `json:",omitempty"`
H uint16 `json:",omitempty"`
I uint32 `json:",omitempty"`
J uint64 `json:",omitempty"`
K float32 `json:",omitempty"`
L float64 `json:",omitempty"`
O string `json:",omitempty"`
P bool `json:",omitempty"`
Q []int `json:",omitempty"`
R map[string]interface{} `json:",omitempty"`
S *struct{} `json:",omitempty"`
T int `json:"t,omitempty"`
}
var v T
v.T = 1
bytes, err := json.Marshal(&v)
assertErr(t, err)
assertEq(t, "struct", `{"t":1}`, string(bytes))
})
t.Run("head_omitempty", func(t *testing.T) {
type T struct {
A *struct{} `json:"a,omitempty"`
}
var v T
bytes, err := json.Marshal(&v)
assertErr(t, err)
assertEq(t, "struct", `{}`, string(bytes))
})
t.Run("pointer_head_omitempty", func(t *testing.T) {
type V struct{}
type U struct {
B *V `json:"b,omitempty"`
}
type T struct {
A *U `json:"a"`
}
bytes, err := json.Marshal(&T{A: &U{}})
assertErr(t, err)
assertEq(t, "struct", `{"a":{}}`, string(bytes))
})
t.Run("head_int_omitempty", func(t *testing.T) {
type T struct {
A int `json:"a,omitempty"`
}
var v T
bytes, err := json.Marshal(&v)
assertErr(t, err)
assertEq(t, "struct", `{}`, string(bytes))
})
})
t.Run("slice", func(t *testing.T) {
t.Run("[]int", func(t *testing.T) {

View File

@ -171,14 +171,16 @@ func (e *Encoder) run(code *opcode) error {
mapiternext(c.iter)
code = c.next
case opStructFieldPtrHead:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHead:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
code = field.end.next
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
@ -410,6 +412,352 @@ func (e *Encoder) run(code *opcode) error {
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadOmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadOmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
p := ptr + field.offset
if p == 0 || *(*uintptr)(unsafe.Pointer(p)) == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
code = field.next
code.ptr = p
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadIntOmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadIntOmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToInt(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeInt(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadInt8OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadInt8OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToInt8(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeInt8(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadInt16OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadInt16OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToInt16(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeInt16(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadInt32OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadInt32OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToInt32(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeInt32(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadInt64OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadInt64OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToInt64(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeInt64(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadUintOmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadUintOmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToUint(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeUint(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadUint8OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadUint8OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToUint8(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeUint8(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadUint16OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadUint16OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToUint16(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeUint16(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadUint32OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadUint32OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToUint32(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeUint32(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadUint64OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadUint64OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToUint64(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeUint64(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadFloat32OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadFloat32OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToFloat32(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeFloat32(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadFloat64OmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadFloat64OmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToFloat64(ptr + field.offset)
if v == 0 {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeFloat64(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadStringOmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadStringOmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToString(ptr + field.offset)
if v == "" {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeEscapedString(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadBoolOmitEmpty:
if code.ptr != 0 {
code.ptr = e.ptrToPtr(code.ptr)
}
fallthrough
case opStructFieldHeadBoolOmitEmpty:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end.next
} else {
e.encodeByte('{')
v := e.ptrToBool(ptr + field.offset)
if !v {
code = field.nextField
} else {
e.encodeBytes(field.key)
e.encodeBool(v)
code = field.next
}
field.nextField.ptr = field.ptr
}
case opStructField:
e.encodeByte(',')
c := code.toStructFieldCode()
@ -515,6 +863,188 @@ func (e *Encoder) run(code *opcode) error {
e.encodeBytes(c.key)
e.encodeBool(e.ptrToBool(c.ptr + c.offset))
code = code.next
case opStructFieldOmitEmpty:
c := code.toStructFieldCode()
p := c.ptr + c.offset
if p == 0 || *(*uintptr)(unsafe.Pointer(p)) == 0 {
code = c.nextField
} else {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
code = code.next
code.ptr = p
}
c.nextField.ptr = c.ptr
case opStructFieldIntOmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToInt(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeInt(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldInt8OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToInt8(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeInt8(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldInt16OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToInt16(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeInt16(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldInt32OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToInt32(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeInt32(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldInt64OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToInt64(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeInt64(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldUintOmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToUint(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeUint(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldUint8OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToUint8(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeUint8(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldUint16OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToUint16(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeUint16(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldUint32OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToUint32(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeUint32(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldUint64OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToUint64(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeUint64(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldFloat32OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToFloat32(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeFloat32(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldFloat64OmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToFloat64(c.ptr + c.offset)
if v != 0 {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeFloat64(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldStringOmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToString(c.ptr + c.offset)
if v != "" {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeEscapedString(v)
}
code = code.next
code.ptr = c.ptr
case opStructFieldBoolOmitEmpty:
c := code.toStructFieldCode()
v := e.ptrToBool(c.ptr + c.offset)
if v {
if e.buf[len(e.buf)-1] != '{' {
e.encodeByte(',')
}
e.encodeBytes(c.key)
e.encodeBool(v)
}
code = code.next
code.ptr = c.ptr
case opStructEnd:
e.encodeByte('}')
code = code.next