zworld/engine/object/property.go

101 lines
1.6 KiB
Go
Raw Normal View History

2024-01-14 22:56:06 +08:00
package object
import (
"fmt"
"reflect"
"zworld/plugins/system/events"
)
type PropValue interface{}
type GenericProp interface {
Type() reflect.Type
GetAny() any
SetAny(any)
}
type Property[T PropValue] struct {
value T
def T
kind reflect.Type
OnChange events.Event[T]
}
var _ GenericProp = &Property[int]{}
func NewProperty[T PropValue](def T) Property[T] {
var empty T
return Property[T]{
value: def,
def: def,
kind: reflect.TypeOf(empty),
}
}
func (p *Property[T]) Get() T {
return p.value
}
func (p *Property[T]) GetAny() any {
return p.value
}
func (p *Property[T]) Set(value T) {
p.value = value
p.OnChange.Emit(value)
}
func (p *Property[T]) SetAny(value any) {
if cast, ok := value.(T); ok {
p.Set(cast)
}
}
func (p *Property[T]) String() string {
return fmt.Sprintf("%v", p.value)
}
func (p *Property[T]) Type() reflect.Type {
return p.kind
}
type PropInfo struct {
GenericProp
Key string
Name string
}
func Properties(target Component) []PropInfo {
t := reflect.TypeOf(target).Elem()
v := reflect.ValueOf(target).Elem()
properties := make([]PropInfo, 0, t.NumField())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if field.Anonymous {
// anonymous fields are not considered
continue
}
if !field.IsExported() {
// only exported fields can be properties
continue
}
value := v.Field(i)
if prop, isProp := value.Addr().Interface().(GenericProp); isProp {
// todo: tags
properties = append(properties, PropInfo{
GenericProp: prop,
Key: field.Name,
Name: field.Name,
})
}
}
return properties
}