From 22f3bba9a816647bda90307b1b6ad9f1ea18777a Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Wed, 19 Aug 2020 19:56:02 +0900 Subject: [PATCH] Support string tag operation --- encode_compile.go | 45 +- encode_vm.go | 1520 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 1548 insertions(+), 17 deletions(-) diff --git a/encode_compile.go b/encode_compile.go index 1f5d4a6..ce028bd 100644 --- a/encode_compile.go +++ b/encode_compile.go @@ -433,10 +433,13 @@ func (e *Encoder) typeToFieldType(op opType) opType { 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) - if isOmitEmpty { + switch { + case tag.isOmitEmpty: headType = headType.headToOmitEmptyHead() + case tag.isString: + headType = headType.headToStringTagHead() } if withIndent { return headType.toIndent() @@ -444,10 +447,13 @@ func (e *Encoder) optimizeStructHeader(op opType, isOmitEmpty, withIndent bool) 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) - if isOmitEmpty { + switch { + case tag.isOmitEmpty: fieldType = fieldType.fieldToOmitEmptyField() + case tag.isString: + fieldType = fieldType.fieldToStringTagField() } if withIndent { return fieldType.toIndent() @@ -481,7 +487,13 @@ func (e *Encoder) compiledCode(typ *rtype, withIndent bool) *opcode { 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 tag := e.getTag(field) opts := strings.Split(tag, ",") @@ -490,16 +502,17 @@ func (e *Encoder) keyNameAndOmitEmptyFromField(field reflect.StructField) (strin keyName = opts[0] } } - isOmitEmpty := false + st := &structTag{key: keyName} 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-- - op := e.optimizeStructHeader(valueCode.op, isOmitEmpty, withIndent) + op := e.optimizeStructHeader(valueCode.op, tag, withIndent) fieldCode.op = op switch op { case opStructFieldHead, @@ -511,9 +524,9 @@ func (e *Encoder) structHeader(fieldCode *structFieldCode, valueCode *opcode, is 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)) - op := e.optimizeStructField(valueCode.op, isOmitEmpty, withIndent) + op := e.optimizeStructField(valueCode.op, tag, withIndent) fieldCode.op = op switch op { case opStructField, @@ -551,7 +564,7 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco if e.isIgnoredStructField(field) { continue } - keyName, isOmitEmpty := e.keyNameAndOmitEmptyFromField(field) + tag := e.structTagFromField(field) fieldType := type2rtype(field.Type) if isPtr && i == 0 { // 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() } } - key := fmt.Sprintf(`"%s":`, keyName) + key := fmt.Sprintf(`"%s":`, tag.key) fieldCode := &structFieldCode{ opcodeHeader: &opcodeHeader{ typ: valueCode.typ, @@ -591,13 +604,13 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco offset: field.Offset, } if fieldIdx == 0 { - code = e.structHeader(fieldCode, valueCode, isOmitEmpty, withIndent) + code = e.structHeader(fieldCode, valueCode, tag, withIndent) head = fieldCode prevField = fieldCode } else { fcode := (*opcode)(unsafe.Pointer(fieldCode)) code.next = fcode - code = e.structField(fieldCode, valueCode, isOmitEmpty, withIndent) + code = e.structField(fieldCode, valueCode, tag, withIndent) prevField.nextField = fcode prevField = fieldCode } diff --git a/encode_vm.go b/encode_vm.go index 64d2731..cfe5dde 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -2752,6 +2752,1061 @@ func (e *Encoder) run(code *opcode) error { } field.nextField.ptr = field.ptr } + case opStructFieldPtrHeadStringTag: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTag: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + p := ptr + field.offset + e.encodeBytes(field.key) + code = field.next + code.ptr = p + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTag: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTag: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + code = field.next + code.ptr = ptr + field.offset + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagInt: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagInt: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt8: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt8: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt8(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagInt8: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagInt8: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt8(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt16: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt16: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt16(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagInt16: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagInt16: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt16(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt32: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt32: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagInt32: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagInt32: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt64: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt64: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt64(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagInt64: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagInt64: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToInt64(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagUint: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagUint: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint8: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint8: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint8(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagUint8: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagUint8: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint8(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint16: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint16: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint16(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagUint16: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagUint16: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint16(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint32: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint32: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagUint32: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagUint32: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint64: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint64: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint64(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagUint64: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagUint64: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToUint64(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagFloat32: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagFloat32: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToFloat32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagFloat32: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagFloat32: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToFloat32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagFloat64: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagFloat64: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + v := e.ptrToFloat64(ptr + field.offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return &UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: strconv.FormatFloat(v, 'g', -1, 64), + } + } + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(v)) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagFloat64: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagFloat64: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + v := e.ptrToFloat64(ptr + field.offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return &UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: strconv.FormatFloat(v, 'g', -1, 64), + } + } + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(v)) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagString: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagString: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(strconv.Quote(e.ptrToString(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagString: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagString: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(strconv.Quote(e.ptrToString(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagBool: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagBool: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToBool(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagBool: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagBool: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + e.encodeString(fmt.Sprint(e.ptrToBool(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagBytes: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagBytes: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + e.encodeBytes(field.key) + s := base64.StdEncoding.EncodeToString( + e.ptrToBytes(ptr + field.offset), + ) + e.encodeByte('"') + e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s))) + e.encodeByte('"') + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagBytes: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagBytes: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + e.encodeBytes(field.key) + s := base64.StdEncoding.EncodeToString( + e.ptrToBytes(ptr + field.offset), + ) + e.encodeByte('"') + e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s))) + e.encodeByte('"') + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagMarshalJSON: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagMarshalJSON: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + p := unsafe.Pointer(ptr + field.offset) + isPtr := code.typ.Kind() == reflect.Ptr + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{typ: code.typ, ptr: p})) + b, err := v.(Marshaler).MarshalJSON() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + if len(b) == 0 { + if isPtr { + return errUnexpectedEndOfJSON( + fmt.Sprintf("error calling MarshalJSON for type %s", code.typ), + 0, + ) + } + e.encodeBytes(field.key) + e.encodeBytes([]byte{'"', '"'}) + code = field.nextField + } else { + var buf bytes.Buffer + if err := compact(&buf, b, true); err != nil { + return err + } + e.encodeString(buf.String()) + code = field.next + } + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagMarshalJSON: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagMarshalJSON: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + p := unsafe.Pointer(ptr + field.offset) + isPtr := code.typ.Kind() == reflect.Ptr + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{typ: code.typ, ptr: p})) + b, err := v.(Marshaler).MarshalJSON() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + if len(b) == 0 { + if isPtr { + return errUnexpectedEndOfJSON( + fmt.Sprintf("error calling MarshalJSON for type %s", code.typ), + 0, + ) + } + e.encodeBytes(field.key) + e.encodeBytes([]byte{'"', '"'}) + code = field.nextField + } else { + var buf bytes.Buffer + if err := compact(&buf, b, true); err != nil { + return err + } + e.encodeBytes(field.key) + e.encodeString(buf.String()) + code = field.next + } + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagMarshalText: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagMarshalText: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeNull() + code = field.end.next + } else { + e.encodeByte('{') + p := unsafe.Pointer(ptr + field.offset) + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{typ: code.typ, ptr: p})) + bytes, err := v.(encoding.TextMarshaler).MarshalText() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + e.encodeBytes(field.key) + e.encodeString(*(*string)(unsafe.Pointer(&bytes))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrAnonymousHeadStringTagMarshalText: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldAnonymousHeadStringTagMarshalText: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + code = field.end.next + } else { + p := unsafe.Pointer(ptr + field.offset) + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{typ: code.typ, ptr: p})) + bytes, err := v.(encoding.TextMarshaler).MarshalText() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + e.encodeBytes(field.key) + e.encodeString(*(*string)(unsafe.Pointer(&bytes))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagIndent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagIndent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + p := ptr + field.offset + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + code = field.next + code.ptr = p + field.nextField.ptr = field.ptr + } + case opStructFieldPtrHeadStringTagIntIndent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagIntIndent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt8Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt8Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt8(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt16Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt16Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt16(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt32Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt32Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagInt64Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagInt64Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt64(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUintIndent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUintIndent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint8Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint8Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint8(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint16Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint16Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint16(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint32Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint32Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagUint64Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagUint64Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint64(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagFloat32Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagFloat32Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToFloat32(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagFloat64Indent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagFloat64Indent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + v := e.ptrToFloat64(ptr + field.offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return &UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: strconv.FormatFloat(v, 'g', -1, 64), + } + } + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(v)) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagStringIndent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagStringIndent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(strconv.Quote(e.ptrToString(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagBoolIndent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagBoolIndent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToBool(ptr + field.offset))) + code = field.next + field.nextField.ptr = ptr + } + case opStructFieldPtrHeadStringTagBytesIndent: + if code.ptr != 0 { + code.ptr = e.ptrToPtr(code.ptr) + } + fallthrough + case opStructFieldHeadStringTagBytesIndent: + field := code.toStructFieldCode() + ptr := field.ptr + if ptr == 0 { + e.encodeIndent(code.indent) + e.encodeNull() + code = field.end.next + } else { + e.encodeBytes([]byte{'{', '\n'}) + e.encodeIndent(code.indent + 1) + e.encodeBytes(field.key) + e.encodeByte(' ') + s := base64.StdEncoding.EncodeToString( + e.ptrToBytes(ptr + field.offset), + ) + e.encodeByte('"') + e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s))) + e.encodeByte('"') + code = field.next + field.nextField.ptr = ptr + } case opStructField: if e.buf[len(e.buf)-1] != '{' { e.encodeByte(',') @@ -3138,6 +4193,33 @@ func (e *Encoder) run(code *opcode) error { e.encodeByte('"') code = code.next c.nextField.ptr = c.ptr + case opStructFieldMarshalJSONIndent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + ptr := c.ptr + c.offset + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + typ: code.typ, + ptr: unsafe.Pointer(ptr), + })) + b, err := v.(Marshaler).MarshalJSON() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + var buf bytes.Buffer + if err := compact(&buf, b, true); err != nil { + return err + } + e.encodeBytes(buf.Bytes()) + code = code.next + c.nextField.ptr = c.ptr case opStructFieldOmitEmpty: c := code.toStructFieldCode() p := c.ptr + c.offset @@ -3622,7 +4704,443 @@ func (e *Encoder) run(code *opcode) error { } code = code.next code.ptr = c.ptr - + case opStructFieldStringTag: + c := code.toStructFieldCode() + p := c.ptr + c.offset + 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 opStructFieldStringTagInt: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToInt(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagInt8: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToInt8(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagInt16: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToInt16(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagInt32: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToInt32(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagInt64: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToInt64(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToUint(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint8: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToUint8(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint16: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToUint16(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint32: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToUint32(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint64: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToUint64(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagFloat32: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToFloat32(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagFloat64: + c := code.toStructFieldCode() + v := e.ptrToFloat64(c.ptr + c.offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return &UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: strconv.FormatFloat(v, 'g', -1, 64), + } + } + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(v)) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagString: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(strconv.Quote(e.ptrToString(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagBool: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + e.encodeString(fmt.Sprint(e.ptrToBool(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagBytes: + c := code.toStructFieldCode() + v := e.ptrToBytes(c.ptr + c.offset) + if e.buf[len(e.buf)-1] != '{' { + e.encodeByte(',') + } + e.encodeBytes(c.key) + s := base64.StdEncoding.EncodeToString(v) + e.encodeByte('"') + e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s))) + e.encodeByte('"') + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagMarshalJSON: + c := code.toStructFieldCode() + ptr := c.ptr + c.offset + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + typ: code.typ, + ptr: unsafe.Pointer(ptr), + })) + b, err := v.(Marshaler).MarshalJSON() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + var buf bytes.Buffer + if err := compact(&buf, b, true); err != nil { + return err + } + e.encodeString(buf.String()) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagMarshalText: + c := code.toStructFieldCode() + ptr := c.ptr + c.offset + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + typ: code.typ, + ptr: unsafe.Pointer(ptr), + })) + bytes, err := v.(encoding.TextMarshaler).MarshalText() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + e.encodeString(*(*string)(unsafe.Pointer(&bytes))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagIndent: + c := code.toStructFieldCode() + p := c.ptr + c.offset + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + code = code.next + code.ptr = p + c.nextField.ptr = c.ptr + case opStructFieldStringTagIntIndent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagInt8Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt8(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagInt16Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt16(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagInt32Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt32(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagInt64Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToInt64(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUintIndent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint8Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint8(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint16Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint16(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint32Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint32(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagUint64Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToUint64(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagFloat32Indent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToFloat32(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagFloat64Indent: + c := code.toStructFieldCode() + v := e.ptrToFloat64(c.ptr + c.offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return &UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: strconv.FormatFloat(v, 'g', -1, 64), + } + } + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(v)) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagStringIndent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + var b bytes.Buffer + enc := NewEncoder(&b) + enc.encodeString(e.ptrToString(c.ptr + c.offset)) + e.encodeString(string(enc.buf)) + enc.release() + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagBoolIndent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + e.encodeString(fmt.Sprint(e.ptrToBool(c.ptr + c.offset))) + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagBytesIndent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + s := base64.StdEncoding.EncodeToString( + e.ptrToBytes(c.ptr + c.offset), + ) + e.encodeByte('"') + e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s))) + e.encodeByte('"') + code = code.next + code.ptr = c.ptr + case opStructFieldStringTagMarshalJSONIndent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + ptr := c.ptr + c.offset + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + typ: code.typ, + ptr: unsafe.Pointer(ptr), + })) + b, err := v.(Marshaler).MarshalJSON() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + var buf bytes.Buffer + if err := compact(&buf, b, true); err != nil { + return err + } + e.encodeString(buf.String()) + code = code.next + c.nextField.ptr = c.ptr + case opStructFieldStringTagMarshalTextIndent: + c := code.toStructFieldCode() + if e.buf[len(e.buf)-2] != '{' { + e.encodeBytes([]byte{',', '\n'}) + } + e.encodeIndent(c.indent) + e.encodeBytes(c.key) + e.encodeByte(' ') + ptr := c.ptr + c.offset + v := *(*interface{})(unsafe.Pointer(&interfaceHeader{ + typ: code.typ, + ptr: unsafe.Pointer(ptr), + })) + bytes, err := v.(encoding.TextMarshaler).MarshalText() + if err != nil { + return &MarshalerError{ + Type: rtype2type(code.typ), + Err: err, + } + } + e.encodeString(*(*string)(unsafe.Pointer(&bytes))) + code = code.next + c.nextField.ptr = c.ptr case opStructEnd: e.encodeByte('}') code = code.next