Description
From #18
make a new embed repo that has embedgen generator to automatically create a map from type name to
any
interface (with option to specify the base interface type name -- e.g.,ki.Ki
) for all embedded struct types -- uses that to implfunc Embed(tpNm string) (any, bool)
method for type, and definesEmbedder
interface with this method. This will be significantly faster than the current reflection-basedki.Embed
method.
Two considerations:
- We want to avoid using strings (error-prone, relatively expensive as a map key) for accessing embedded types.
- We might still want to be able to get a type from a string name, for saving / loading arbitrary Ki trees, where the type name for every struct is saved and then used at load time to create the objects.
Plan: make a simple lightweight ki-specific Type and TypeRegistry, with unique uint64
handles for key types, which are used as map keys for the embed function. This means that Embed must be specific to Ki and not a general-purpose tool.
in goki/ki
repo, in the one top-level 'ki' package #18:
var (
// TypeIDCounter is atomically incremented for assigning new Type.ID numbers
TypeIDCounter uint64
// TypeRegistry provides a way to look up types from string short names (package.Type, e.g., gi.Button)
TypeRegistry = map[string]*Type{}
)
// Type represents a Ki type
type Type struct {
Name string `desc:"type name, using the short form (e.g., gi.Button)"`
ID uint64 `desc:"unique type ID number -- use as a key handle for embed map"`
Instance Ki `desc:"instance of the Ki type -- call Clone() on this to make a new token"`
}
// NewType creates a new Type for given instance. This call is auto-generated for each Ki type.
func NewType(nm string, inst Ki) *Type {
inst.InitName(inst, nm)
tp := &Type{Name: nm, Instance: inst}
tp.ID = atomic.AddUint64(&TypeIDCounter, 1)
TypeRegistry[nm] = tp
return tp
}
// example auto-gen code for each Ki type:
// var TypeButton = ki.NewType("gi.Button", &Button{})
// func NewButton(parent ki.Ki, name string) *Button {
// if parent == nil {
// b := &Button{}; b.InitName(b, name); return b
// } else {
// return parent.AddNewChild(TypeButton, name).(*Button)
// }
// }
// func (k *Button) NewInstance() ki.Ki { b := &Button{}; b.InitNode(b); return b }
// var ButtonEmbeds map[uint64]ki.Ki
// func (k *Button) Embed(tp *ki.Type) ki.Ki {
// if ButtonEmbeds == nil {
// ButtonEmbeds = make(map[uint64]ki.Ki)
// ButtonEmbeds[TypeWidget.ID] = &k.Widget // note: must do delayed construction of global embeds var to get valid IDs
// ...
// }
// return ButtonEmbeds[tp.ID] // will be nil if not there -- for known embeds it is *much* easier to be able to use return directly in inline expressions, so not using the additional bool here
// }
// NewInstance returns a new instance of given type
// Note: otherwise impossible to generate new instance generically, unless using reflection
func (tp *Type) NewInstance() Ki {
return tp.Instance.NewInstance()
}
// ReflectType returns the reflect type of a given Ki Type
func (tp *Type) ReflectType() reflect.Type {
return reflect.TypeOf(tp.Instance).Elem()
}
// TypeByName re
5547
turns a ki Type by name (package.Type, e,g. gi.Button), or error if not found
func TypeByName(nm string) (*Type, error) {
tp, ok := TypeRegistry[nm]
if !ok {
return nil, fmt.Errorf("Ki Type: %s not found", nm)
}
return tp, nil
}
// note: replace all instances of reflect.Type in ki code with this ki.Type