WIP: Implements class in napi-go #10

Draft
Sirherobrine23 wants to merge 1 commits from class into main
3 changed files with 135 additions and 0 deletions
Showing only changes of commit ec1d76e51e - Show all commits

79
class.go Normal file
View File

@ -0,0 +1,79 @@
package napi
import (
"fmt"
"reflect"
"unsafe"
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
)
type (
PropertyDescriptor = napi.PropertyDescriptor
ClassType interface {
Contructor(env EnvType, this ValueType, args []ValueType) (*Object, error)
}
Class[T ClassType] struct {
value
Class T
classReflect reflect.Type
}
)
const (
PropertyAttributesDefault = napi.Default
PropertyAttributesWritable = napi.Writable
PropertyAttributesEnumerable = napi.Enumerable
PropertyAttributesConfigurable = napi.Configurable
PropertyAttributesStatic = napi.Static
PropertyAttributesDefaultMethod = napi.DefaultMethod
PropertyAttributesDefaultJSProperty = napi.DefaultJSProperty
)
func CreateClass[T ClassType](env EnvType, propertys []PropertyDescriptor) (*Class[T], error) {
ptrType := reflect.TypeFor[T]()
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:
return nil, fmt.Errorf("type %s is not a struct", ptrType.Name())
}
startStruct := &Class[T]{classReflect: ptrType}
value, status := napi.DefineClass(env.NapiValue(), ptrType.Name(),
func(env napi.Env, info napi.CallbackInfo) napi.Value {
startStruct.Class = reflect.New(ptrType).Interface().(T)
cbInfo, status := napi.GetCbInfo(env, info)
if err := status.ToError(); err != nil {
ThrowError(N_APIEnv(env), "", err.Error())
return nil
}
gonapiEnv := N_APIEnv(env)
this := N_APIValue(gonapiEnv, cbInfo.This)
args := make([]ValueType, len(cbInfo.Args))
for i, cbArg := range cbInfo.Args {
args[i] = N_APIValue(gonapiEnv, cbArg)
}
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 {
return nil, err
}
startStruct.value = N_APIValue(env, value)
return startStruct, nil
}

View File

@ -0,0 +1,29 @@
package main
import (
_ "unsafe"
_ "sirherobrine23.com.br/Sirherobrine23/napi-go/entry"
"sirherobrine23.com.br/Sirherobrine23/napi-go"
)
func main() {}
//go:linkname Register sirherobrine23.com.br/Sirherobrine23/napi-go/entry.Register
func Register(env napi.EnvType, export *napi.Object) {
class, err := napi.CreateClass[*ClassTest](env, []napi.PropertyDescriptor{})
if err != nil {
panic(err)
}
export.Set("class", class)
}
type ClassTest struct{}
func (class *ClassTest) Contructor(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (*napi.Object, error) {
obj, _ := napi.CreateObject(env)
return obj, nil
}

27
internal/napi/class.go Normal file
View File

@ -0,0 +1,27 @@
package napi
// #include <node/node_api.h>
import "C"
import "unsafe"
func DefineClass(env Env, name string, constructor Callback, Property []PropertyDescriptor) (Value, Status) {
var pro *C.napi_property_descriptor
if len(Property) > 0 {
pro = (*C.napi_property_descriptor)(unsafe.Pointer(&Property[0]))
}
var result Value
call := &constructor
status := Status(C.napi_define_class(
C.napi_env(env),
C.CString(name),
C.size_t(len(name)),
C.napi_callback(unsafe.Pointer(call)),
nil,
C.size_t(len(Property)),
pro,
(*C.napi_value)(unsafe.Pointer(&result)),
))
return result, status
}