Files
CLIProxyAPI/internal/config/clone.go
2026-06-17 02:39:04 +08:00

82 lines
1.7 KiB
Go

package config
import (
"reflect"
"gopkg.in/yaml.v3"
)
var yamlNodeType = reflect.TypeOf(yaml.Node{})
// CloneForRuntime returns an independent in-memory snapshot of the full config.
func (cfg *Config) CloneForRuntime() *Config {
if cfg == nil {
return nil
}
cloned := cloneRuntimeValue(reflect.ValueOf(cfg))
return cloned.Interface().(*Config)
}
func cloneRuntimeValue(v reflect.Value) reflect.Value {
if !v.IsValid() {
return v
}
if v.Type() == yamlNodeType {
node := v.Interface().(yaml.Node)
return reflect.ValueOf(*deepCopyNode(&node))
}
switch v.Kind() {
case reflect.Pointer:
if v.IsNil() {
return reflect.Zero(v.Type())
}
out := reflect.New(v.Type().Elem())
out.Elem().Set(cloneRuntimeValue(v.Elem()))
return out
case reflect.Interface:
if v.IsNil() {
return reflect.Zero(v.Type())
}
return cloneRuntimeValue(v.Elem())
case reflect.Struct:
out := reflect.New(v.Type()).Elem()
for i := 0; i < v.NumField(); i++ {
dst := out.Field(i)
if !dst.CanSet() {
return v
}
dst.Set(cloneRuntimeValue(v.Field(i)))
}
return out
case reflect.Slice:
if v.IsNil() {
return reflect.Zero(v.Type())
}
out := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
for i := 0; i < v.Len(); i++ {
out.Index(i).Set(cloneRuntimeValue(v.Index(i)))
}
return out
case reflect.Array:
out := reflect.New(v.Type()).Elem()
for i := 0; i < v.Len(); i++ {
out.Index(i).Set(cloneRuntimeValue(v.Index(i)))
}
return out
case reflect.Map:
if v.IsNil() {
return reflect.Zero(v.Type())
}
out := reflect.MakeMapWithSize(v.Type(), v.Len())
iter := v.MapRange()
for iter.Next() {
out.SetMapIndex(cloneRuntimeValue(iter.Key()), cloneRuntimeValue(iter.Value()))
}
return out
default:
return v
}
}