0x1998 - MANAGER
Düzenlenen Dosya: flatted.go
package flatted import ( "encoding/json" "reflect" "sort" "strconv" "strings" ) // flattedIndex is a internal type used to distinguish between // actual strings and flatted indices during the reconstruction phase. type flattedIndex string // Stringify converts a Go value into a specialized flatted JSON string. func Stringify(value any, replacer any, space any) (string, error) { knownKeys := []any{} knownValues := []string{} input := []any{} index := func(v any) string { input = append(input, v) idx := strconv.Itoa(len(input) - 1) knownKeys = append(knownKeys, v) knownValues = append(knownValues, idx) return idx } relate := func(v any) any { if v == nil { return nil } rv := reflect.ValueOf(v) kind := rv.Kind() if kind == reflect.String || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Ptr { for i, k := range knownKeys { if kind == reflect.String { if k == v { return knownValues[i] } } else { rk := reflect.ValueOf(k) if rk.Kind() == kind && rk.Pointer() == rv.Pointer() { return knownValues[i] } } } return index(v) } return v } transform := func(v any) any { rv := reflect.ValueOf(v) if !rv.IsValid() { return nil } if _, ok := v.(json.Marshaler); ok { return v } // Dereference pointers to process the underlying Slice, Map, or Array for rv.Kind() == reflect.Ptr && !rv.IsNil() { rv = rv.Elem() } switch rv.Kind() { case reflect.Slice, reflect.Array: res := make([]any, rv.Len()) for i := 0; i < rv.Len(); i++ { res[i] = relate(rv.Index(i).Interface()) } return res case reflect.Map: res := make(map[string]any) keys := rv.MapKeys() sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() }) whitelist, isWhitelist := replacer.([]string) for _, key := range keys { kStr := key.String() if isWhitelist { found := false for _, w := range whitelist { if w == kStr { found = true break } } if !found { continue } } res[kStr] = relate(rv.MapIndex(key).Interface()) } return res case reflect.Struct: res := make(map[string]any) t := rv.Type() for i := 0; i < rv.NumField(); i++ { field := t.Field(i) if field.PkgPath != "" { continue } name := field.Name if tag := field.Tag.Get("json"); tag != "" { name = strings.Split(tag, ",")[0] } res[name] = relate(rv.Field(i).Interface()) } return res default: return v } } index(value) output := []any{} for i := 0; i < len(input); i++ { output = append(output, transform(input[i])) } var b []byte var err error indent := "" if s, ok := space.(string); ok { indent = s } else if i, ok := space.(int); ok { indent = strings.Repeat(" ", i) } if indent != "" { b, err = json.MarshalIndent(output, "", indent) } else { b, err = json.Marshal(output) } if err != nil { return "", err } return string(b), nil } // Parse converts a specialized flatted string into a Go value. func Parse(text string, reviver func(key string, value any) any) (any, error) { var jsonInput []any if err := json.Unmarshal([]byte(text), &jsonInput); err != nil { return nil, err } var wrap func(any) any wrap = func(v any) any { if s, ok := v.(string); ok { return flattedIndex(s) } if arr, ok := v.([]any); ok { for i, item := range arr { arr[i] = wrap(item) } return arr } if m, ok := v.(map[string]any); ok { for k, item := range m { m[k] = wrap(item) } return m } return v } wrapped := make([]any, len(jsonInput)) for i, v := range jsonInput { wrapped[i] = wrap(v) } input := make([]any, len(wrapped)) for i, v := range wrapped { if fi, ok := v.(flattedIndex); ok { input[i] = string(fi) } else { input[i] = v } } if len(input) == 0 { return nil, nil } value := input[0] rv := reflect.ValueOf(value) if rv.IsValid() && (rv.Kind() == reflect.Slice || rv.Kind() == reflect.Map) { set := make(map[uintptr]bool) set[rv.Pointer()] = true res := loop(value, input, set) if reviver != nil { return revive("", res, reviver), nil } return res, nil } if reviver != nil { return reviver("", value), nil } return value, nil } func revive(key string, value any, reviver func(k string, v any) any) any { if arr, ok := value.([]any); ok { for i, v := range arr { arr[i] = revive(strconv.Itoa(i), v, reviver) } } else if m, ok := value.(map[string]any); ok { keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { m[k] = revive(k, m[k], reviver) } } return reviver(key, value) } func loop(value any, input []any, set map[uintptr]bool) any { if arr, ok := value.([]any); ok { for i, v := range arr { if fi, ok := v.(flattedIndex); ok { idx, _ := strconv.Atoi(string(fi)) arr[i] = ref(input[idx], input, set) } } return arr } if m, ok := value.(map[string]any); ok { for k, v := range m { if fi, ok := v.(flattedIndex); ok { idx, _ := strconv.Atoi(string(fi)) m[k] = ref(input[idx], input, set) } } return m } return value } func ref(value any, input []any, set map[uintptr]bool) any { rv := reflect.ValueOf(value) if rv.IsValid() && (rv.Kind() == reflect.Slice || rv.Kind() == reflect.Map) { ptr := rv.Pointer() if !set[ptr] { set[ptr] = true return loop(value, input, set) } } return value } // ToJSON converts a generic value into a JSON serializable object without losing recursion. func ToJSON(value any) (any, error) { s, err := Stringify(value, nil, nil) if err != nil { return nil, err } var res any err = json.Unmarshal([]byte(s), &res) return res, err } // FromJSON converts a previously serialized object with recursion into a recursive one. func FromJSON(value any) (any, error) { b, err := json.Marshal(value) if err != nil { return nil, err } return Parse(string(b), nil) }
geri dön