68 lines
2.0 KiB
Go
68 lines
2.0 KiB
Go
|
|
package engine
|
||
|
|
|
||
|
|
import (
|
||
|
|
"cmp"
|
||
|
|
"reflect"
|
||
|
|
"slices"
|
||
|
|
)
|
||
|
|
|
||
|
|
type secretSlotAccess uint8
|
||
|
|
|
||
|
|
const (
|
||
|
|
secretSlotsReadOnly secretSlotAccess = iota
|
||
|
|
secretSlotsWritable
|
||
|
|
)
|
||
|
|
|
||
|
|
// walkSecretSlots visits schema-bound secret references. Writable traversal
|
||
|
|
// copies map entries into addressable values and writes them back; read-only
|
||
|
|
// traversal borrows them. The visitor owns the operation performed at each slot.
|
||
|
|
func walkSecretSlots(root reflect.Value, descriptor *typeDescriptor, access secretSlotAccess, visit func(reflect.Value, Path, bool)) {
|
||
|
|
var walk func(reflect.Value, *typeDescriptor, Path, bool)
|
||
|
|
walk = func(value reflect.Value, descriptor *typeDescriptor, path Path, optional bool) {
|
||
|
|
if descriptor.kind == descriptorPointer {
|
||
|
|
if !value.IsNil() {
|
||
|
|
walk(value.Elem(), descriptor.element, path, descriptor.element.kind == descriptorSecret)
|
||
|
|
}
|
||
|
|
return
|
||
|
|
}
|
||
|
|
switch descriptor.kind {
|
||
|
|
case descriptorSecret:
|
||
|
|
visit(value, path, optional)
|
||
|
|
case descriptorStruct:
|
||
|
|
for _, member := range descriptor.members {
|
||
|
|
memberPath := path
|
||
|
|
if !member.inline {
|
||
|
|
memberPath = path.Key(member.name)
|
||
|
|
}
|
||
|
|
walk(value.Field(member.index), member.descriptor, memberPath, false)
|
||
|
|
}
|
||
|
|
case descriptorMap:
|
||
|
|
if value.IsNil() {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
keys := value.MapKeys()
|
||
|
|
slices.SortFunc(keys, func(left, right reflect.Value) int { return cmp.Compare(left.String(), right.String()) })
|
||
|
|
for _, key := range keys {
|
||
|
|
entry := value.MapIndex(key)
|
||
|
|
if access == secretSlotsWritable {
|
||
|
|
copy := reflect.New(value.Type().Elem()).Elem()
|
||
|
|
copy.Set(entry)
|
||
|
|
entry = copy
|
||
|
|
}
|
||
|
|
walk(entry, descriptor.element, path.Key(key.String()), false)
|
||
|
|
if access == secretSlotsWritable {
|
||
|
|
value.SetMapIndex(key, entry)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case descriptorSlice, descriptorArray:
|
||
|
|
if descriptor.kind == descriptorSlice && value.IsNil() {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
for index := 0; index < value.Len(); index++ {
|
||
|
|
walk(value.Index(index), descriptor.element, path.Index(index), false)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
walk(root, descriptor, Path{}, false)
|
||
|
|
}
|