Implement canonical projection and detached copies

This commit is contained in:
2026-09-06 19:44:36 +00:00
parent 2b65876a7d
commit 15172294b5
8 changed files with 1059 additions and 23 deletions

View File

@@ -28,7 +28,8 @@ const (
)
type schemaDescriptor struct {
root *typeDescriptor
root *typeDescriptor
types map[reflect.Type]*typeDescriptor
}
type typeDescriptor struct {
@@ -36,11 +37,19 @@ type typeDescriptor struct {
kind descriptorKind
element *typeDescriptor
length int
members []structMember
fields []fieldDescriptor
fieldByName map[string]int
inlineMap *fieldDescriptor
}
type structMember struct {
index int
name string
descriptor *typeDescriptor
inline bool
}
type fieldDescriptor struct {
name string
index []int
@@ -76,7 +85,7 @@ func buildSchema(root reflect.Type) (*schemaDescriptor, *schemaIssue) {
if descriptor.kind != descriptorStruct && descriptor.kind != descriptorMap {
return nil, &schemaIssue{code: CodeSchemaRoot, message: "configuration root must be a structural struct or string-keyed map"}
}
return &schemaDescriptor{root: descriptor}, nil
return &schemaDescriptor{root: descriptor, types: builder.cache}, nil
}
type schemaBuilder struct {
@@ -228,6 +237,11 @@ func (b *schemaBuilder) describeFields(descriptor *typeDescriptor, current refle
}
descriptor.inlineMap = &nested
}
memberType, memberIssue := b.describe(field.Type, path)
if memberIssue != nil {
return memberIssue
}
descriptor.members = append(descriptor.members, structMember{index: i, descriptor: memberType, inline: true})
case reflect.Map:
if inlineType.Key().Kind() != reflect.String {
return &schemaIssue{code: CodeSchemaInline, path: path.clone(), message: "inline map must have string keys"}
@@ -241,6 +255,7 @@ func (b *schemaBuilder) describeFields(descriptor *typeDescriptor, current refle
return childIssue
}
descriptor.inlineMap = &fieldDescriptor{index: []int{i}, descriptor: fieldType, secret: secret, inlineMap: true}
descriptor.members = append(descriptor.members, structMember{index: i, descriptor: fieldType, inline: true})
default:
return &schemaIssue{code: CodeSchemaInline, path: path.clone(), message: "inline field must be a struct, pointer to struct, or string-keyed map"}
}
@@ -255,6 +270,7 @@ func (b *schemaBuilder) describeFields(descriptor *typeDescriptor, current refle
if issue := addField(descriptor, fieldDescriptor{name: name, index: []int{i}, descriptor: fieldType, secret: secret}, path); issue != nil {
return issue
}
descriptor.members = append(descriptor.members, structMember{index: i, name: name, descriptor: fieldType})
}
return nil
}