Implement canonical projection and detached copies
This commit is contained in:
20
schema.go
20
schema.go
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user