Ctrl K
ComunidadGuías…

internal/config/clone.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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
	}
}