83 lines
1.9 KiB
Go
83 lines
1.9 KiB
Go
package data
|
|
|
|
import (
|
|
"strconv"
|
|
"unsafe"
|
|
|
|
"aego/core/ids"
|
|
"aego/format/aetext"
|
|
"aego/scene/sceneio"
|
|
"aego/schema"
|
|
)
|
|
|
|
func Fresh(td *schema.TypeDescriptor) unsafe.Pointer {
|
|
return fresh(td)
|
|
}
|
|
|
|
func NewValue(reg *schema.Registry, td *schema.TypeDescriptor, fields []aetext.Field) (unsafe.Pointer, []string) {
|
|
p := fresh(td)
|
|
return p, applyFields(reg, td, p, fields, "")
|
|
}
|
|
|
|
func applyFields(reg *schema.Registry, td *schema.TypeDescriptor, p unsafe.Pointer, fields []aetext.Field, prefix string) []string {
|
|
var issues []string
|
|
for _, f := range fields {
|
|
fd, ok := td.Field(f.Name)
|
|
if !ok {
|
|
issues = append(issues, prefix+"unknown field "+f.Name+" is ignored")
|
|
continue
|
|
}
|
|
v, err := sceneio.ReadValue(reg, fd, f.Value)
|
|
if err == nil {
|
|
err = fd.Set(p, v)
|
|
}
|
|
if err != nil {
|
|
issues = append(issues, prefix+f.Name+": "+err.Error())
|
|
}
|
|
}
|
|
return issues
|
|
}
|
|
|
|
func (l *Library) Compose(id ids.AssetID, d *Doc) (*Record, error) {
|
|
td, err := l.typeOf(d.Type)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rec := &Record{ID: id, Type: td, Ptr: fresh(td), Base: d.Base}
|
|
if d.Base.IsZero() {
|
|
rec.Origin = fresh(td)
|
|
} else {
|
|
if err := l.chain(id, d.Base); err != nil {
|
|
return nil, err
|
|
}
|
|
base, err := l.Record(d.Base)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if base.Type != td {
|
|
return nil, failf(id, "its base has type "+base.Type.FullName+", it has "+td.FullName)
|
|
}
|
|
td.Copy(rec.Ptr, base.Ptr)
|
|
rec.Origin = base.Ptr
|
|
}
|
|
rec.Issues = applyFields(l.reg, td, rec.Ptr, d.Fields, "")
|
|
return rec, nil
|
|
}
|
|
|
|
func (l *Library) chain(id, base ids.AssetID) error {
|
|
for b, n := base, 0; !b.IsZero(); n++ {
|
|
switch {
|
|
case b == id:
|
|
return failf(id, "its base chain refers back to itself")
|
|
case n >= MaxDepth:
|
|
return failf(id, "its base chain is deeper than "+strconv.Itoa(MaxDepth))
|
|
}
|
|
r, err := l.Record(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b = r.Base
|
|
}
|
|
return nil
|
|
}
|