186 lines
4.5 KiB
Go
186 lines
4.5 KiB
Go
package jsonpack
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/samber/lo"
|
|
)
|
|
|
|
type JsonEncode struct {
|
|
strings []string
|
|
integers []string
|
|
floats []string
|
|
}
|
|
|
|
func (oJsonEncode *JsonEncode) astBuilder(item any) (AstToken, error) {
|
|
itemType := reflect.ValueOf(item).Kind()
|
|
|
|
if item == nil {
|
|
return AstToken{category: "null", index: TOKEN_NULL}, nil
|
|
}
|
|
|
|
if itemType == reflect.Slice {
|
|
tokens := []AstToken{}
|
|
|
|
value := reflect.ValueOf(item)
|
|
|
|
for i := 0; i < value.Len(); i++ {
|
|
// value.Index(i).Interface() 把 value 转换为 interface{} 类型
|
|
if resp, err := oJsonEncode.astBuilder(value.Index(i).Interface()); err == nil {
|
|
tokens = append(tokens, resp)
|
|
} else {
|
|
return AstToken{}, err
|
|
}
|
|
}
|
|
|
|
// return tokens, nil
|
|
|
|
// Create a new sub-AST of type Array (@)
|
|
return AstToken{category: "@", child: tokens}, nil
|
|
}
|
|
|
|
if itemType == reflect.Map {
|
|
// Create a new sub-AST of type Object ($)
|
|
// tokens := []any{AstToken{category: "$"}}
|
|
tokens := []AstToken{}
|
|
|
|
iter := reflect.ValueOf(item).MapRange()
|
|
|
|
for iter.Next() {
|
|
if resp, err := oJsonEncode.astBuilder(iter.Key().Interface()); err == nil {
|
|
tokens = append(tokens, resp)
|
|
} else {
|
|
return AstToken{}, err
|
|
}
|
|
|
|
if resp, err := oJsonEncode.astBuilder(iter.Value().Interface()); err == nil {
|
|
tokens = append(tokens, resp)
|
|
} else {
|
|
return AstToken{}, err
|
|
}
|
|
}
|
|
|
|
// return tokens, nil
|
|
return AstToken{category: "$", child: tokens}, nil
|
|
}
|
|
|
|
if item == "" {
|
|
return AstToken{category: "empty", index: TOKEN_EMPTY_STRING}, nil
|
|
}
|
|
|
|
if itemType == reflect.String {
|
|
value := item.(string)
|
|
index := lo.IndexOf[string](oJsonEncode.strings, value)
|
|
|
|
if index == -1 {
|
|
oJsonEncode.strings = append(oJsonEncode.strings, astEncode(value))
|
|
index = len(oJsonEncode.strings) - 1
|
|
}
|
|
|
|
return AstToken{category: "strings", index: index}, nil
|
|
}
|
|
|
|
switch itemType {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
|
value := astBase10to36(item.(int))
|
|
index := lo.IndexOf[string](oJsonEncode.integers, value)
|
|
|
|
if index == -1 {
|
|
oJsonEncode.integers = append(oJsonEncode.integers, value)
|
|
index = len(oJsonEncode.integers) - 1
|
|
}
|
|
|
|
return AstToken{category: "integers", index: index}, nil
|
|
}
|
|
|
|
if itemType == reflect.Float32 || itemType == reflect.Float64 {
|
|
value := fmt.Sprintf("%v", item.(float64))
|
|
index := lo.IndexOf[string](oJsonEncode.floats, value)
|
|
|
|
if index == -1 {
|
|
// 浮点数不用转36进制
|
|
oJsonEncode.floats = append(oJsonEncode.floats, value)
|
|
index = len(oJsonEncode.floats) - 1
|
|
}
|
|
|
|
return AstToken{category: "floats", index: index}, nil
|
|
}
|
|
|
|
if itemType == reflect.Bool {
|
|
if item.(bool) {
|
|
return AstToken{category: "boolean", index: TOKEN_TRUE}, nil
|
|
} else {
|
|
return AstToken{category: "boolean", index: TOKEN_FALSE}, nil
|
|
}
|
|
}
|
|
|
|
return AstToken{}, errors.New(fmt.Sprintln("未知类型:", itemType, item))
|
|
}
|
|
|
|
func (oJsonEncode *JsonEncode) astParser(token AstToken) (string, error) {
|
|
|
|
if token.category == "@" || token.category == "$" {
|
|
var packed strings.Builder
|
|
|
|
packed.WriteString(token.category)
|
|
|
|
childPacked := []string{}
|
|
|
|
for _, tk := range token.child {
|
|
if resp, err := oJsonEncode.astParser(tk); err == nil {
|
|
childPacked = append(childPacked, resp)
|
|
} else {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
packed.WriteString(strings.Join(childPacked, "|"))
|
|
packed.WriteString("]")
|
|
|
|
return packed.String(), nil
|
|
}
|
|
|
|
switch token.category {
|
|
case "strings":
|
|
return astBase10to36(token.index), nil
|
|
case "integers":
|
|
return astBase10to36(token.index + len(oJsonEncode.strings)), nil
|
|
case "floats":
|
|
return astBase10to36(token.index + len(oJsonEncode.strings) + len(oJsonEncode.integers)), nil
|
|
case "boolean":
|
|
return fmt.Sprintf("%v", token.index), nil
|
|
case "null":
|
|
return fmt.Sprintf("%v", TOKEN_NULL), nil
|
|
case "empty":
|
|
return fmt.Sprintf("%v", TOKEN_EMPTY_STRING), nil
|
|
}
|
|
|
|
return "", errors.New(fmt.Sprintln("未知类型:", token.category))
|
|
}
|
|
|
|
func (oJsonEncode *JsonEncode) toString(token AstToken) (string, error) {
|
|
str, err := oJsonEncode.astParser(token)
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var packed strings.Builder
|
|
|
|
packed.WriteString(strings.Join(oJsonEncode.strings, "|"))
|
|
packed.WriteString("^")
|
|
packed.WriteString(strings.Join(oJsonEncode.integers, "|"))
|
|
packed.WriteString("^")
|
|
packed.WriteString(strings.Join(oJsonEncode.floats, "|"))
|
|
packed.WriteString("^")
|
|
|
|
packed.WriteString(str)
|
|
|
|
return packed.String(), nil
|
|
}
|