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 }