Support string tag operation

This commit is contained in:
Masaaki Goshima 2020-08-19 19:56:02 +09:00
parent 8f7cb46c5d
commit 22f3bba9a8
2 changed files with 1548 additions and 17 deletions

View File

@ -433,10 +433,13 @@ func (e *Encoder) typeToFieldType(op opType) opType {
return opStructField return opStructField
} }
func (e *Encoder) optimizeStructHeader(op opType, isOmitEmpty, withIndent bool) opType { func (e *Encoder) optimizeStructHeader(op opType, tag *structTag, withIndent bool) opType {
headType := e.typeToHeaderType(op) headType := e.typeToHeaderType(op)
if isOmitEmpty { switch {
case tag.isOmitEmpty:
headType = headType.headToOmitEmptyHead() headType = headType.headToOmitEmptyHead()
case tag.isString:
headType = headType.headToStringTagHead()
} }
if withIndent { if withIndent {
return headType.toIndent() return headType.toIndent()
@ -444,10 +447,13 @@ func (e *Encoder) optimizeStructHeader(op opType, isOmitEmpty, withIndent bool)
return headType return headType
} }
func (e *Encoder) optimizeStructField(op opType, isOmitEmpty, withIndent bool) opType { func (e *Encoder) optimizeStructField(op opType, tag *structTag, withIndent bool) opType {
fieldType := e.typeToFieldType(op) fieldType := e.typeToFieldType(op)
if isOmitEmpty { switch {
case tag.isOmitEmpty:
fieldType = fieldType.fieldToOmitEmptyField() fieldType = fieldType.fieldToOmitEmptyField()
case tag.isString:
fieldType = fieldType.fieldToStringTagField()
} }
if withIndent { if withIndent {
return fieldType.toIndent() return fieldType.toIndent()
@ -481,7 +487,13 @@ func (e *Encoder) compiledCode(typ *rtype, withIndent bool) *opcode {
return nil return nil
} }
func (e *Encoder) keyNameAndOmitEmptyFromField(field reflect.StructField) (string, bool) { type structTag struct {
key string
isOmitEmpty bool
isString bool
}
func (e *Encoder) structTagFromField(field reflect.StructField) *structTag {
keyName := field.Name keyName := field.Name
tag := e.getTag(field) tag := e.getTag(field)
opts := strings.Split(tag, ",") opts := strings.Split(tag, ",")
@ -490,16 +502,17 @@ func (e *Encoder) keyNameAndOmitEmptyFromField(field reflect.StructField) (strin
keyName = opts[0] keyName = opts[0]
} }
} }
isOmitEmpty := false st := &structTag{key: keyName}
if len(opts) > 1 { if len(opts) > 1 {
isOmitEmpty = opts[1] == "omitempty" st.isOmitEmpty = opts[1] == "omitempty"
st.isString = opts[1] == "string"
} }
return keyName, isOmitEmpty return st
} }
func (e *Encoder) structHeader(fieldCode *structFieldCode, valueCode *opcode, isOmitEmpty, withIndent bool) *opcode { func (e *Encoder) structHeader(fieldCode *structFieldCode, valueCode *opcode, tag *structTag, withIndent bool) *opcode {
fieldCode.indent-- fieldCode.indent--
op := e.optimizeStructHeader(valueCode.op, isOmitEmpty, withIndent) op := e.optimizeStructHeader(valueCode.op, tag, withIndent)
fieldCode.op = op fieldCode.op = op
switch op { switch op {
case opStructFieldHead, case opStructFieldHead,
@ -511,9 +524,9 @@ func (e *Encoder) structHeader(fieldCode *structFieldCode, valueCode *opcode, is
return (*opcode)(unsafe.Pointer(fieldCode)) return (*opcode)(unsafe.Pointer(fieldCode))
} }
func (e *Encoder) structField(fieldCode *structFieldCode, valueCode *opcode, isOmitEmpty, withIndent bool) *opcode { func (e *Encoder) structField(fieldCode *structFieldCode, valueCode *opcode, tag *structTag, withIndent bool) *opcode {
code := (*opcode)(unsafe.Pointer(fieldCode)) code := (*opcode)(unsafe.Pointer(fieldCode))
op := e.optimizeStructField(valueCode.op, isOmitEmpty, withIndent) op := e.optimizeStructField(valueCode.op, tag, withIndent)
fieldCode.op = op fieldCode.op = op
switch op { switch op {
case opStructField, case opStructField,
@ -551,7 +564,7 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
if e.isIgnoredStructField(field) { if e.isIgnoredStructField(field) {
continue continue
} }
keyName, isOmitEmpty := e.keyNameAndOmitEmptyFromField(field) tag := e.structTagFromField(field)
fieldType := type2rtype(field.Type) fieldType := type2rtype(field.Type)
if isPtr && i == 0 { if isPtr && i == 0 {
// head field of pointer structure at top level // head field of pointer structure at top level
@ -579,7 +592,7 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
f = f.nextField.toStructFieldCode() f = f.nextField.toStructFieldCode()
} }
} }
key := fmt.Sprintf(`"%s":`, keyName) key := fmt.Sprintf(`"%s":`, tag.key)
fieldCode := &structFieldCode{ fieldCode := &structFieldCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
typ: valueCode.typ, typ: valueCode.typ,
@ -591,13 +604,13 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
offset: field.Offset, offset: field.Offset,
} }
if fieldIdx == 0 { if fieldIdx == 0 {
code = e.structHeader(fieldCode, valueCode, isOmitEmpty, withIndent) code = e.structHeader(fieldCode, valueCode, tag, withIndent)
head = fieldCode head = fieldCode
prevField = fieldCode prevField = fieldCode
} else { } else {
fcode := (*opcode)(unsafe.Pointer(fieldCode)) fcode := (*opcode)(unsafe.Pointer(fieldCode))
code.next = fcode code.next = fcode
code = e.structField(fieldCode, valueCode, isOmitEmpty, withIndent) code = e.structField(fieldCode, valueCode, tag, withIndent)
prevField.nextField = fcode prevField.nextField = fcode
prevField = fieldCode prevField = fieldCode
} }

File diff suppressed because it is too large Load Diff