jsonpack/jsonpackEncode.go
2023-04-15 00:06:52 +08:00

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
}