WIP: Implements class in napi-go #10
150
class.go
150
class.go
@@ -3,77 +3,123 @@ package napi
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type Class[T ClassType] struct {
|
||||||
PropertyDescriptor = napi.PropertyDescriptor
|
value
|
||||||
|
Class T
|
||||||
|
}
|
||||||
|
|
||||||
ClassType interface {
|
type PropertyAttributes int
|
||||||
Contructor(env EnvType, this ValueType, args []ValueType) (*Object, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
Class[T ClassType] struct {
|
type PropertyDescriptor struct {
|
||||||
value
|
Name string
|
||||||
Class T
|
Method Callback
|
||||||
classReflect reflect.Type
|
Getter Callback
|
||||||
}
|
Setter Callback
|
||||||
)
|
Value ValueType
|
||||||
|
Attributes PropertyAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base to class declaration
|
||||||
|
type ClassType interface {
|
||||||
|
Contructor(*CallbackInfo) (*Object, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ClassFuncMathod = reflect.TypeFor[Callback]()
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PropertyAttributesDefault = napi.Default
|
PropertyAttributesWritable = PropertyAttributes(napi.Writable)
|
||||||
PropertyAttributesWritable = napi.Writable
|
PropertyAttributesEnumerable = PropertyAttributes(napi.Enumerable)
|
||||||
PropertyAttributesEnumerable = napi.Enumerable
|
PropertyAttributesConfigurable = PropertyAttributes(napi.Configurable)
|
||||||
PropertyAttributesConfigurable = napi.Configurable
|
PropertyAttributesStatic = PropertyAttributes(napi.Static)
|
||||||
PropertyAttributesStatic = napi.Static
|
PropertyAttributesDefault = PropertyAttributes(napi.Default)
|
||||||
PropertyAttributesDefaultMethod = napi.DefaultMethod
|
PropertyAttributesDefaultMethod = PropertyAttributes(napi.DefaultMethod)
|
||||||
PropertyAttributesDefaultJSProperty = napi.DefaultJSProperty
|
PropertyAttributesDefaultJSProperty = PropertyAttributes(napi.DefaultJSProperty)
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateClass[T ClassType](env EnvType, propertys []PropertyDescriptor) (*Class[T], error) {
|
func CreateClass[T ClassType](env EnvType) (*Class[T], error) {
|
||||||
ptrType := reflect.TypeFor[T]()
|
ptrType := reflect.TypeFor[T]()
|
||||||
switch ptrType.Kind() {
|
switch ptrType.Kind() {
|
||||||
case reflect.Struct:
|
|
||||||
case reflect.Pointer:
|
|
||||||
if ptrType = ptrType.Elem(); ptrType.Kind() != reflect.Struct {
|
|
||||||
return nil, fmt.Errorf("type %s is not a struct", ptrType.Name())
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("type %s is not a struct", ptrType.Name())
|
return nil, fmt.Errorf("type %s is not a struct", ptrType.Name())
|
||||||
|
case reflect.Pointer:
|
||||||
|
elem := ptrType.Elem()
|
||||||
|
if elem.Kind() == reflect.Struct {
|
||||||
|
return classMount[T](env, elem)
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case reflect.Struct:
|
||||||
|
return classMount[T](env, ptrType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func classMount[T ClassType](env EnvType, ptr reflect.Type) (*Class[T], error) {
|
||||||
|
valueOf := reflect.New(ptr)
|
||||||
|
|
||||||
|
var propertys []*PropertyDescriptor
|
||||||
|
for methodIndex := range ptr.NumMethod() {
|
||||||
|
method := ptr.Method(methodIndex)
|
||||||
|
if method.Type.Kind() != reflect.Func || !method.IsExported() {
|
||||||
|
continue
|
||||||
|
} else if !method.Type.Implements(ClassFuncMathod) {
|
||||||
|
continue
|
||||||
|
} else if method.Name == "Contructor" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
propertys = append(propertys, &PropertyDescriptor{
|
||||||
|
Name: method.Name,
|
||||||
|
Attributes: PropertyAttributes(PropertyAttributesStatic),
|
||||||
|
Method: valueOf.Method(methodIndex).Interface().(Callback),
|
||||||
|
Getter: nil,
|
||||||
|
Setter: nil,
|
||||||
|
Value: nil,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
startStruct := &Class[T]{classReflect: ptrType}
|
var napiAtr []napi.PropertyDescriptor
|
||||||
value, status := napi.DefineClass(env.NapiValue(), ptrType.Name(),
|
for _, value := range propertys {
|
||||||
func(env napi.Env, info napi.CallbackInfo) napi.Value {
|
name, err := CreateString(env, value.Name)
|
||||||
startStruct.Class = reflect.New(ptrType).Interface().(T)
|
if err != nil {
|
||||||
cbInfo, status := napi.GetCbInfo(env, info)
|
return nil, err
|
||||||
if err := status.ToError(); err != nil {
|
}
|
||||||
ThrowError(N_APIEnv(env), "", err.Error())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
gonapiEnv := N_APIEnv(env)
|
method, err := CreateFunction(env, value.Name, value.Method)
|
||||||
this := N_APIValue(gonapiEnv, cbInfo.This)
|
if err != nil {
|
||||||
args := make([]ValueType, len(cbInfo.Args))
|
return nil, err
|
||||||
for i, cbArg := range cbInfo.Args {
|
}
|
||||||
args[i] = N_APIValue(gonapiEnv, cbArg)
|
|
||||||
}
|
napiAtr = append(napiAtr, napi.PropertyDescriptor{
|
||||||
|
Utf8name: value.Name,
|
||||||
|
Name: name.NapiValue(),
|
||||||
|
Method: method.NapiCallback(),
|
||||||
|
Attributes: napi.PropertyAttributes(value.Attributes),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
jsConstruct, err := CreateFunction(env, "constructor", func(ci *CallbackInfo) (ValueType, error) {
|
||||||
|
res := valueOf.MethodByName("Contructor").Call([]reflect.Value{reflect.ValueOf(ci)})
|
||||||
|
obj, err := res[0].Interface().(*Object), res[1].Interface().(error)
|
||||||
|
return N_APIValue(obj.Env(), obj.NapiValue()), err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
jsValue, status := napi.DefineClass(env.NapiValue(), ptr.Name(),
|
||||||
|
jsConstruct.fn,
|
||||||
|
napiAtr,
|
||||||
|
)
|
||||||
|
|
||||||
res, err := startStruct.Class.Contructor(gonapiEnv, this, args)
|
|
||||||
if err != nil {
|
|
||||||
ThrowError(gonapiEnv, "", err.Error())
|
|
||||||
} else if res == nil {
|
|
||||||
und, _ := gonapiEnv.Undefined()
|
|
||||||
return und.NapiValue()
|
|
||||||
}
|
|
||||||
napi.Wrap(env, res.NapiValue(), unsafe.Pointer(startStruct), nil, nil)
|
|
||||||
return res.NapiValue()
|
|
||||||
}, propertys)
|
|
||||||
if err := status.ToError(); err != nil {
|
if err := status.ToError(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
startStruct.value = N_APIValue(env, value)
|
|
||||||
return startStruct, nil
|
return &Class[T]{
|
||||||
|
value: N_APIValue(env, jsValue),
|
||||||
|
Class: valueOf.Interface().(T),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
@@ -3,16 +3,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
_ "sirherobrine23.com.br/Sirherobrine23/napi-go/entry"
|
_ "sirherobrine23.com.br/Sirherobrine23/napi-go/module"
|
||||||
|
|
||||||
"sirherobrine23.com.br/Sirherobrine23/napi-go"
|
"sirherobrine23.com.br/Sirherobrine23/napi-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {}
|
func main() {}
|
||||||
|
|
||||||
//go:linkname Register sirherobrine23.com.br/Sirherobrine23/napi-go/entry.Register
|
//go:linkname Register sirherobrine23.com.br/Sirherobrine23/napi-go/module.Register
|
||||||
func Register(env napi.EnvType, export *napi.Object) {
|
func Register(env napi.EnvType, export *napi.Object) {
|
||||||
class, err := napi.CreateClass[*ClassTest](env, []napi.PropertyDescriptor{})
|
class, err := napi.CreateClass[*ClassTest](env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -22,8 +22,8 @@ func Register(env napi.EnvType, export *napi.Object) {
|
|||||||
|
|
||||||
type ClassTest struct{}
|
type ClassTest struct{}
|
||||||
|
|
||||||
func (class *ClassTest) Contructor(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (*napi.Object, error) {
|
func (class *ClassTest) Contructor(ci *napi.CallbackInfo) (*napi.Object, error) {
|
||||||
obj, _ := napi.CreateObject(env)
|
obj, _ := napi.CreateObject(ci.Env)
|
||||||
|
|
||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user