gin/codec/json/jsoniter.go
2025-10-29 16:27:07 +08:00

325 lines
8.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2025 Gin Core Team. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
//go:build jsoniter
package json
import (
"io"
jsoniter "github.com/json-iterator/go"
)
// Package indicates what library is being used for JSON encoding.
const Package = "github.com/json-iterator/go"
func containsAF(s string) bool {
for _, char := range s {
if char >= 'a' && char <= 'f' {
return true
}
}
return false
}
// HexStringEncoder 自定义编码器将 int64 类型编码为十六进制字符串或者把16进制转为int64
type HexStringEncoder struct {
IsInt64Pointer bool //源数据为 *int64
}
// Encode 实现 jsoniter.ValEncoder 接口
func (e *HexStringEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
if ptr == nil {
stream.WriteNil()
return
}
// Convert *int64 value to a 16-byte hexadecimal string
if e.IsInt64Pointer {
pp := (**int64)(ptr)
if *pp == nil {
stream.WriteNil()
return
}
stream.WriteString(fmt.Sprintf("%x", **pp))
return
}
// Convert int64 value to a 16-byte hexadecimal string
value := *(*int64)(ptr)
if value == 0 {
stream.WriteString("0") //0值特殊处理
} else {
stream.WriteString(fmt.Sprintf("%x", value))
}
}
func (e *HexStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return ptr == nil || *(*int64)(ptr) == 0
}
func (codec *HexStringEncoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
if valueType == jsoniter.StringValue {
str := iter.ReadString()
var i int64
var err error
if len(str) < 17 || containsAF(str) {
i, err = strconv.ParseInt(str, 16, 64)
if err != nil {
i = 0
}
} else {
i, err = strconv.ParseInt(str, 10, 64)
if err != nil {
i = 0
}
}
*((*int64)(ptr)) = i
} else if valueType == jsoniter.NumberValue {
*((*int64)(ptr)) = iter.ReadInt64()
} else {
*((*int64)(ptr)) = 0
}
}
// EmptyObjectEncoder 实现一个编码器当字段值为nil时写入空对象{}
type EmptyObjectEncoder struct {
encoder jsoniter.ValEncoder
}
func (encoder *EmptyObjectEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
// If the pointer points to nil, write an empty object.
if *(*uintptr)(ptr) == 0 {
stream.WriteRaw("{}")
return
}
// Fallback to default encoding.
encoder.encoder.Encode(ptr, stream)
}
func (encoder *EmptyObjectEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.encoder.IsEmpty(ptr)
}
type EmptyArrayEncoder struct {
encoder jsoniter.ValEncoder
}
func (encoder *EmptyArrayEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
// If the pointer points to nil, write an empty object.
if *(*uintptr)(ptr) == 0 {
stream.WriteRaw("[]")
return
}
// Fallback to default encoding.
encoder.encoder.Encode(ptr, stream)
}
func (encoder *EmptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.encoder.IsEmpty(ptr)
}
// 空数组64位数组
type EmptyArrayInt64Encoder struct {
encoder jsoniter.ValEncoder
decoder jsoniter.ValDecoder
}
func (encoder *EmptyArrayInt64Encoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
// If the pointer points to nil, write an empty object.
if *(*uintptr)(ptr) == 0 {
stream.WriteRaw("[]")
return
}
//循环数组
slice := (*[]int64)(ptr)
strSlice := make([]string, len(*slice))
for i, v := range *slice {
if v == 0 {
strSlice[i] = "0"
} else {
strSlice[i] = fmt.Sprintf("%x", v)
}
}
jsonData, err := jsonInstance.Marshal(strSlice)
if err != nil {
encoder.encoder.Encode(ptr, stream)
return
}
stream.WriteRaw(string(jsonData))
}
func (codec *EmptyArrayInt64Encoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
//str := iter.ReadString()
valueList := []int64{}
for iter.ReadArray() {
val := iter.Read()
if iter.Error != nil {
break
}
if str, ok := val.(string); ok {
//含有a-f或者正好16位使用16进制解析
if len(str) < 17 || containsAF(str) {
intVal, err := strconv.ParseInt(str, 16, 64)
if err != nil {
continue
}
valueList = append(valueList, intVal)
} else {
intVal, err := strconv.ParseInt(str, 10, 64)
if err != nil {
continue
}
valueList = append(valueList, intVal)
}
}
}
// 将ptr解析为*[]int64类型的指针
ptrToSlice := (*[]int64)(ptr)
// 使用reflect包将ptr的内容替换为slice
reflect.ValueOf(ptrToSlice).Elem().Set(reflect.ValueOf(valueList))
}
func (encoder *EmptyArrayInt64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.encoder.IsEmpty(ptr)
}
type ToStringEncoder struct{}
func (codec *ToStringEncoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
if valueType == jsoniter.StringValue {
str := iter.ReadString()
*((*string)(ptr)) = str
} else {
valueAsString := iter.ReadAny().ToString()
*((*string)(ptr)) = valueAsString
}
}
type ToBoolEncoder struct {
decoder jsoniter.ValDecoder
DefaultVal bool
}
func (codec *ToBoolEncoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
if valueType == jsoniter.BoolValue {
codec.decoder.Decode(ptr, iter)
} else if valueType == jsoniter.NumberValue {
i := iter.ReadInt()
var myBool bool
if i > 0 {
myBool = true
} else {
myBool = false
}
*((*bool)(ptr)) = myBool
} else if valueType == jsoniter.StringValue {
str := strings.ToLower(iter.ReadString())
var myBool bool
if str == "true" || str == "1" {
myBool = true
} else if str == "false" || str == "0" || str == "-1" {
myBool = false
} else {
myBool = codec.DefaultVal
}
*((*bool)(ptr)) = myBool
} else {
str := strings.ToLower(iter.ReadAny().ToString())
var myBool bool
if str == "true" || str == "1" {
myBool = true
} else if str == "false" || str == "0" || str == "-1" {
myBool = false
} else {
myBool = codec.DefaultVal
}
*((*bool)(ptr)) = myBool
}
}
// HexStringExtension 检查 struct 字段tags为相应的 int64 字段应用 HexStringEncoder
type ApipostExtension struct {
jsoniter.DummyExtension
}
// UpdateStructDescriptor 修改 struct 字段的编码/解码器
func (extension *ApipostExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
for _, binding := range structDescriptor.Fields {
// 检查字段类型和 tag
if binding.Field.Type().Kind() == reflect.Int64 {
//处理64位转换
if strings.Contains(binding.Field.Tag().Get("json"), "hexstring") {
binding.Encoder = &HexStringEncoder{}
binding.Decoder = &HexStringEncoder{}
}
} else if binding.Field.Type().Kind() == reflect.Ptr || binding.Field.Type().Kind() == reflect.Interface {
if strings.Contains(binding.Field.Tag().Get("json"), "hexstring") && binding.Field.Type().Type1().Elem().Kind() == reflect.Int64 { //处理*int64位转换
binding.Encoder = &HexStringEncoder{IsInt64Pointer: true}
} else if strings.Contains(binding.Field.Tag().Get("json"), "emptyobject") { //处理空对象
binding.Encoder = &EmptyObjectEncoder{binding.Encoder}
}
} else if binding.Field.Type().Kind() == reflect.Slice || binding.Field.Type().Kind() == reflect.Array {
//处理空数组
if binding.Field.Type().Type1().Elem().String() == "int64" {
//强制转64数组
int64SliceEncode := &EmptyArrayInt64Encoder{binding.Encoder, binding.Decoder}
binding.Encoder = int64SliceEncode
binding.Decoder = int64SliceEncode
} else if strings.Contains(binding.Field.Tag().Get("json"), "emptyarray") {
binding.Encoder = &EmptyArrayEncoder{binding.Encoder}
}
} else if binding.Field.Type().Kind() == reflect.String {
if strings.Contains(binding.Field.Tag().Get("json"), "tostring") {
binding.Decoder = &ToStringEncoder{}
}
} else if binding.Field.Type().Kind() == reflect.Bool {
tagStr := binding.Field.Tag().Get("json")
if strings.Contains(tagStr, "tofalse") {
binding.Decoder = &ToBoolEncoder{binding.Decoder, false}
} else if strings.Contains(tagStr, "totrue") {
binding.Decoder = &ToBoolEncoder{binding.Decoder, true}
}
}
}
}
func init() {
json.RegisterExtension(&ApipostExtension{})
API = jsoniterApi{}
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
type jsoniterApi struct{}
func (j jsoniterApi) Marshal(v any) ([]byte, error) {
return json.Marshal(v)
}
func (j jsoniterApi) Unmarshal(data []byte, v any) error {
return json.Unmarshal(data, v)
}
func (j jsoniterApi) MarshalIndent(v any, prefix, indent string) ([]byte, error) {
return json.MarshalIndent(v, prefix, indent)
}
func (j jsoniterApi) NewEncoder(writer io.Writer) Encoder {
return json.NewEncoder(writer)
}
func (j jsoniterApi) NewDecoder(reader io.Reader) Decoder {
return json.NewDecoder(reader)
}