98 lines
2.2 KiB
Go
98 lines
2.2 KiB
Go
package jsonvalue
|
|
|
|
import "reflect"
|
|
|
|
func cloneTrustedMap(src map[string]any) map[string]any {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
out := make(map[string]any, len(src))
|
|
for k, v := range src {
|
|
out[k] = CloneTrusted(v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// CloneTrusted detaches a previously accepted value without revalidating it.
|
|
func CloneTrusted(value any) any {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
switch v := value.(type) {
|
|
case map[string]any:
|
|
return cloneTrustedMap(v)
|
|
case []any:
|
|
out := make([]any, len(v))
|
|
for i, item := range v {
|
|
out[i] = CloneTrusted(item)
|
|
}
|
|
return out
|
|
case []string:
|
|
if v == nil {
|
|
return []string(nil)
|
|
}
|
|
return append([]string{}, v...)
|
|
case []byte:
|
|
if v == nil {
|
|
return []byte(nil)
|
|
}
|
|
return append([]byte{}, v...)
|
|
default:
|
|
return cloneTrustedReflect(reflect.ValueOf(value)).Interface()
|
|
}
|
|
}
|
|
|
|
func cloneTrustedReflect(value reflect.Value) reflect.Value {
|
|
if !value.IsValid() {
|
|
return value
|
|
}
|
|
|
|
switch value.Kind() {
|
|
case reflect.Interface:
|
|
if value.IsNil() {
|
|
return reflect.Zero(value.Type())
|
|
}
|
|
copied := cloneTrustedReflect(value.Elem())
|
|
if copied.IsValid() && copied.Type().AssignableTo(value.Type()) {
|
|
return copied
|
|
}
|
|
out := reflect.New(value.Type()).Elem()
|
|
out.Set(copied)
|
|
return out
|
|
case reflect.Pointer:
|
|
if value.IsNil() {
|
|
return reflect.Zero(value.Type())
|
|
}
|
|
out := reflect.New(value.Type().Elem())
|
|
out.Elem().Set(cloneTrustedReflect(value.Elem()))
|
|
return out
|
|
case reflect.Map:
|
|
if value.IsNil() {
|
|
return reflect.Zero(value.Type())
|
|
}
|
|
out := reflect.MakeMapWithSize(value.Type(), value.Len())
|
|
iter := value.MapRange()
|
|
for iter.Next() {
|
|
out.SetMapIndex(cloneTrustedReflect(iter.Key()), cloneTrustedReflect(iter.Value()))
|
|
}
|
|
return out
|
|
case reflect.Slice:
|
|
if value.IsNil() {
|
|
return reflect.Zero(value.Type())
|
|
}
|
|
out := reflect.MakeSlice(value.Type(), value.Len(), value.Cap())
|
|
for i := 0; i < value.Len(); i++ {
|
|
out.Index(i).Set(cloneTrustedReflect(value.Index(i)))
|
|
}
|
|
return out
|
|
case reflect.Array:
|
|
out := reflect.New(value.Type()).Elem()
|
|
for i := 0; i < value.Len(); i++ {
|
|
out.Index(i).Set(cloneTrustedReflect(value.Index(i)))
|
|
}
|
|
return out
|
|
default:
|
|
return value
|
|
}
|
|
}
|