package paneldecl import "git.yeij.top/AskaEth/Cyrene_v2/pkg/plugins/sdk" // 本文件是目录的**拷贝语义**:存进来时拷一次、发出去时再拷一次。 // // 为什么要两次:§5.2.1 的不变量是「`List` 返回的必须是拷贝」——调用方(gateway / 插件管理器) // 拿着结果做过滤或补字段时,绝不能改到目录内部状态;反向同理,插件管理器注册后继续改自己 // 那份声明,也不能影响目录里的快照。声明是嵌套结构(sections → fields → 指针字段), // 浅拷贝会把内部切片暴露出去,所以这里逐层深拷。 // clonePanel 深拷一份面板声明。 func clonePanel(p sdk.Panel) sdk.Panel { out := p out.When = cloneWhen(p.When) if p.Sections != nil { out.Sections = make([]sdk.Section, len(p.Sections)) for i, s := range p.Sections { out.Sections[i] = cloneSection(s) } } return out } // cloneSection 深拷一个区块(切片与指针字段都要换新)。 func cloneSection(s sdk.Section) sdk.Section { out := s if s.Fields != nil { out.Fields = make([]sdk.Field, len(s.Fields)) for i, f := range s.Fields { out.Fields[i] = cloneField(f) } } if s.Columns != nil { out.Columns = make([]sdk.Column, len(s.Columns)) copy(out.Columns, s.Columns) } if s.RowActions != nil { out.RowActions = make([]sdk.RowAction, len(s.RowActions)) copy(out.RowActions, s.RowActions) } if s.Submit != nil { submit := *s.Submit out.Submit = &submit } if s.Source != nil { source := *s.Source out.Source = &source } return out } // cloneField 深拷一个字段(Default 是 any,可能装着 map/slice)。 func cloneField(f sdk.Field) sdk.Field { out := f out.Default = cloneValue(f.Default) if f.Min != nil { min := *f.Min out.Min = &min } if f.Max != nil { max := *f.Max out.Max = &max } return out } // cloneWhen 深拷 when(Enabled 是指针,共享指针等于共享可变状态)。 func cloneWhen(w *sdk.When) *sdk.When { if w == nil { return nil } out := &sdk.When{} if w.Enabled != nil { enabled := *w.Enabled out.Enabled = &enabled } return out } // cloneValue 递归拷贝默认值里的容器。标量(字符串/数字/布尔)本身不可变,直接返回。 // // 未覆盖的类型(声明由 Go 代码直接构造时可能塞进任意类型)按原值返回并在文档里写明: // 本包只承诺「结构声明不可被调用方改坏」,不承诺替调用方深拷它自己塞进来的自定义类型。 func cloneValue(v any) any { switch val := v.(type) { case map[string]any: out := make(map[string]any, len(val)) for k, item := range val { out[k] = cloneValue(item) } return out case map[string]string: out := make(map[string]string, len(val)) for k, item := range val { out[k] = item } return out case []any: out := make([]any, len(val)) for i, item := range val { out[i] = cloneValue(item) } return out case []string: out := make([]string, len(val)) copy(out, val) return out default: return v } }