Update pkg to same Node addon Header #8
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.node
|
1
LICENSE
1
LICENSE
@ -1,6 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Akshay Ganeshen
|
||||
Copyright (c) 2024 Matheus Sampaio Queiroga
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
79
README.md
79
README.md
@ -1,82 +1,3 @@
|
||||
# napi-go
|
||||
|
||||
A Go library for building Node.js Native Addons using Node-API.
|
||||
|
||||
## Usage
|
||||
|
||||
Use `go get` to install the library:
|
||||
|
||||
```sh
|
||||
go get -u github.com/akshayganeshen/napi-go
|
||||
```
|
||||
|
||||
Then use the library to define handlers:
|
||||
|
||||
```go
|
||||
package handlers
|
||||
|
||||
import "github.com/akshayganeshen/napi-go"
|
||||
|
||||
func MyHandler(env napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Next, create a `main.go` that registers all module exports:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/akshayganeshen/napi-go/entry"
|
||||
|
||||
func init() {
|
||||
entry.Export("myHandler", MyHandler)
|
||||
}
|
||||
|
||||
func main() {}
|
||||
```
|
||||
|
||||
Finally, build the Node.js addon using `go build`:
|
||||
|
||||
```sh
|
||||
go build -buildmode=c-shared -o "example.node" .
|
||||
```
|
||||
|
||||
The output `.node` file can now be imported via `require`:
|
||||
|
||||
```js
|
||||
const example = require("./example.node");
|
||||
|
||||
example.myHandler();
|
||||
```
|
||||
|
||||
### JS Helpers
|
||||
|
||||
In addition to the Node-API exposed via package `napi`, the `napi-go/js`
|
||||
package provides functions similar to the `syscall/js` standard library.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/akshayganeshen/napi-go/entry"
|
||||
"github.com/akshayganeshen/napi-go/js"
|
||||
)
|
||||
|
||||
func init() {
|
||||
entry.Export("myCallback", js.AsCallback(MyCallback))
|
||||
}
|
||||
|
||||
func MyCallback(env js.Env, this js.Value, args []js.Value) any {
|
||||
return map[string]any{
|
||||
"message": "hello world",
|
||||
"args": args,
|
||||
}
|
||||
}
|
||||
|
||||
func main() {}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Check out the example addons in [`docs/examples`](docs/examples).
|
||||
|
85
array.go
Normal file
85
array.go
Normal file
@ -0,0 +1,85 @@
|
||||
package napi
|
||||
|
||||
import (
|
||||
"iter"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type Array struct{ value }
|
||||
|
||||
// Convert [ValueType] to [*Array].
|
||||
func ToArray(o ValueType) *Array { return &Array{o} }
|
||||
|
||||
// Create Array.
|
||||
func CreateArray(env EnvType, size ...int) (*Array, error) {
|
||||
sizeOf := 0
|
||||
if len(size) > 0 {
|
||||
sizeOf = size[0]
|
||||
}
|
||||
napiValue, err := napi.Value(nil), error(nil)
|
||||
if sizeOf == 0 {
|
||||
napiValue, err = mustValueErr(napi.CreateArray(env.NapiValue()))
|
||||
} else {
|
||||
napiValue, err = mustValueErr(napi.CreateArrayWithLength(env.NapiValue(), sizeOf))
|
||||
}
|
||||
// Check error exists
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToArray(N_APIValue(env, napiValue)), nil
|
||||
}
|
||||
|
||||
// Get array length.
|
||||
func (arr *Array) Length() (int, error) {
|
||||
return mustValueErr(napi.GetArrayLength(arr.NapiEnv(), arr.NapiValue()))
|
||||
}
|
||||
|
||||
// Delete index elemente from array.
|
||||
func (arr *Array) Delete(index int) (bool, error) {
|
||||
return mustValueErr(napi.DeleteElement(arr.NapiEnv(), arr.NapiValue(), index))
|
||||
}
|
||||
|
||||
// Set value in index
|
||||
func (arr *Array) Set(index int, value ValueType) error {
|
||||
return singleMustValueErr(napi.SetElement(arr.NapiEnv(), arr.NapiValue(), index, value.NapiValue()))
|
||||
}
|
||||
|
||||
// Get Value from index
|
||||
func (arr *Array) Get(index int) (ValueType, error) {
|
||||
napiValue, err := mustValueErr(napi.GetElement(arr.NapiEnv(), arr.NapiValue(), index))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return N_APIValue(arr.Env(), napiValue), nil
|
||||
}
|
||||
|
||||
// Get values with [iter.Seq]
|
||||
func (arr *Array) Seq() iter.Seq[ValueType] {
|
||||
length, err := arr.Length()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return func(yield func(ValueType) bool) {
|
||||
for index := range length {
|
||||
if value, err := arr.Get(index); err == nil {
|
||||
if !yield(value) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (arr *Array) Append(values ...ValueType) error {
|
||||
length, err := arr.Length()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for valueIndex := range values {
|
||||
if err = arr.Set(length+valueIndex, values[valueIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
20
boolean.go
Normal file
20
boolean.go
Normal file
@ -0,0 +1,20 @@
|
||||
package napi
|
||||
|
||||
import "sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
|
||||
type Boolean struct{ value }
|
||||
|
||||
// Convert [ValueType] to [*Boolean]
|
||||
func ToBoolean(o ValueType) *Boolean { return &Boolean{o} }
|
||||
|
||||
func CreateBoolean(env EnvType, value bool) (*Boolean, error) {
|
||||
v, err := mustValueErr(napi.GetBoolean(env.NapiValue(), value))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToBoolean(N_APIValue(env, v)), nil
|
||||
}
|
||||
|
||||
func (bo *Boolean) Value() (bool, error) {
|
||||
return mustValueErr(napi.GetValueBool(bo.NapiEnv(), bo.NapiValue()))
|
||||
}
|
36
buffer.go
Normal file
36
buffer.go
Normal file
@ -0,0 +1,36 @@
|
||||
package napi
|
||||
|
||||
import "sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
|
||||
type Buffer struct{ value }
|
||||
|
||||
// Convert [ValueType] to [*Buffer].
|
||||
func ToBuffer(o ValueType) *Buffer { return &Buffer{o} }
|
||||
|
||||
// Create new Buffer with length
|
||||
func CreateBuffer(env EnvType, length int) (*Buffer, error) {
|
||||
napiValue, err := mustValueErr(napi.CreateBuffer(env.NapiValue(), length))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToBuffer(N_APIValue(env, napiValue)), nil
|
||||
}
|
||||
|
||||
// Copy []byte to Node::Buffer struct
|
||||
func CopyBuffer(env EnvType, buff []byte) (*Buffer, error) {
|
||||
napiValue, err := mustValueErr(napi.CreateBufferCopy(env.NapiValue(), buff))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToBuffer(N_APIValue(env, napiValue)), nil
|
||||
}
|
||||
|
||||
// Get size of buffer
|
||||
func (buff *Buffer) Length() (int, error) {
|
||||
return mustValueErr(napi.GetBufferInfoSize(buff.NapiEnv(), buff.NapiValue()))
|
||||
}
|
||||
|
||||
// return []byte from Buffer value
|
||||
func (buff *Buffer) Data() ([]byte, error) {
|
||||
return mustValueErr(napi.GetBufferInfoData(buff.NapiEnv(), buff.NapiValue()))
|
||||
}
|
186
c++/napi-inl.deprecated.h
Normal file
186
c++/napi-inl.deprecated.h
Normal file
@ -0,0 +1,186 @@
|
||||
#ifndef SRC_NAPI_INL_DEPRECATED_H_
|
||||
#define SRC_NAPI_INL_DEPRECATED_H_
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// PropertyDescriptor class
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Getter>
|
||||
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||
const char* utf8name,
|
||||
Getter getter,
|
||||
napi_property_attributes attributes,
|
||||
void* /*data*/) {
|
||||
using CbData = details::CallbackData<Getter, Napi::Value>;
|
||||
// TODO: Delete when the function is destroyed
|
||||
auto callbackData = new CbData({getter, nullptr});
|
||||
|
||||
return PropertyDescriptor({utf8name,
|
||||
nullptr,
|
||||
nullptr,
|
||||
CbData::Wrapper,
|
||||
nullptr,
|
||||
nullptr,
|
||||
attributes,
|
||||
callbackData});
|
||||
}
|
||||
|
||||
template <typename Getter>
|
||||
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||
const std::string& utf8name,
|
||||
Getter getter,
|
||||
napi_property_attributes attributes,
|
||||
void* data) {
|
||||
return Accessor(utf8name.c_str(), getter, attributes, data);
|
||||
}
|
||||
|
||||
template <typename Getter>
|
||||
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||
napi_value name,
|
||||
Getter getter,
|
||||
napi_property_attributes attributes,
|
||||
void* /*data*/) {
|
||||
using CbData = details::CallbackData<Getter, Napi::Value>;
|
||||
// TODO: Delete when the function is destroyed
|
||||
auto callbackData = new CbData({getter, nullptr});
|
||||
|
||||
return PropertyDescriptor({nullptr,
|
||||
name,
|
||||
nullptr,
|
||||
CbData::Wrapper,
|
||||
nullptr,
|
||||
nullptr,
|
||||
attributes,
|
||||
callbackData});
|
||||
}
|
||||
|
||||
template <typename Getter>
|
||||
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||
Name name, Getter getter, napi_property_attributes attributes, void* data) {
|
||||
napi_value nameValue = name;
|
||||
return PropertyDescriptor::Accessor(nameValue, getter, attributes, data);
|
||||
}
|
||||
|
||||
template <typename Getter, typename Setter>
|
||||
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||
const char* utf8name,
|
||||
Getter getter,
|
||||
Setter setter,
|
||||
napi_property_attributes attributes,
|
||||
void* /*data*/) {
|
||||
using CbData = details::AccessorCallbackData<Getter, Setter>;
|
||||
// TODO: Delete when the function is destroyed
|
||||
auto callbackData = new CbData({getter, setter, nullptr});
|
||||
|
||||
return PropertyDescriptor({utf8name,
|
||||
nullptr,
|
||||
nullptr,
|
||||
CbData::GetterWrapper,
|
||||
CbData::SetterWrapper,
|
||||
nullptr,
|
||||
attributes,
|
||||
callbackData});
|
||||
}
|
||||
|
||||
template <typename Getter, typename Setter>
|
||||
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||
const std::string& utf8name,
|
||||
Getter getter,
|
||||
Setter setter,
|
||||
napi_property_attributes attributes,
|
||||
void* data) {
|
||||
return Accessor(utf8name.c_str(), getter, setter, attributes, data);
|
||||
}
|
||||
|
||||
template <typename Getter, typename Setter>
|
||||
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||
napi_value name,
|
||||
Getter getter,
|
||||
Setter setter,
|
||||
napi_property_attributes attributes,
|
||||
void* /*data*/) {
|
||||
using CbData = details::AccessorCallbackData<Getter, Setter>;
|
||||
// TODO: Delete when the function is destroyed
|
||||
auto callbackData = new CbData({getter, setter, nullptr});
|
||||
|
||||
return PropertyDescriptor({nullptr,
|
||||
name,
|
||||
nullptr,
|
||||
CbData::GetterWrapper,
|
||||
CbData::SetterWrapper,
|
||||
nullptr,
|
||||
attributes,
|
||||
callbackData});
|
||||
}
|
||||
|
||||
template <typename Getter, typename Setter>
|
||||
inline PropertyDescriptor PropertyDescriptor::Accessor(
|
||||
Name name,
|
||||
Getter getter,
|
||||
Setter setter,
|
||||
napi_property_attributes attributes,
|
||||
void* data) {
|
||||
napi_value nameValue = name;
|
||||
return PropertyDescriptor::Accessor(
|
||||
nameValue, getter, setter, attributes, data);
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
inline PropertyDescriptor PropertyDescriptor::Function(
|
||||
const char* utf8name,
|
||||
Callable cb,
|
||||
napi_property_attributes attributes,
|
||||
void* /*data*/) {
|
||||
using ReturnType = decltype(cb(CallbackInfo(nullptr, nullptr)));
|
||||
using CbData = details::CallbackData<Callable, ReturnType>;
|
||||
// TODO: Delete when the function is destroyed
|
||||
auto callbackData = new CbData({cb, nullptr});
|
||||
|
||||
return PropertyDescriptor({utf8name,
|
||||
nullptr,
|
||||
CbData::Wrapper,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
attributes,
|
||||
callbackData});
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
inline PropertyDescriptor PropertyDescriptor::Function(
|
||||
const std::string& utf8name,
|
||||
Callable cb,
|
||||
napi_property_attributes attributes,
|
||||
void* data) {
|
||||
return Function(utf8name.c_str(), cb, attributes, data);
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
inline PropertyDescriptor PropertyDescriptor::Function(
|
||||
napi_value name,
|
||||
Callable cb,
|
||||
napi_property_attributes attributes,
|
||||
void* /*data*/) {
|
||||
using ReturnType = decltype(cb(CallbackInfo(nullptr, nullptr)));
|
||||
using CbData = details::CallbackData<Callable, ReturnType>;
|
||||
// TODO: Delete when the function is destroyed
|
||||
auto callbackData = new CbData({cb, nullptr});
|
||||
|
||||
return PropertyDescriptor({nullptr,
|
||||
name,
|
||||
CbData::Wrapper,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
attributes,
|
||||
callbackData});
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
inline PropertyDescriptor PropertyDescriptor::Function(
|
||||
Name name, Callable cb, napi_property_attributes attributes, void* data) {
|
||||
napi_value nameValue = name;
|
||||
return PropertyDescriptor::Function(nameValue, cb, attributes, data);
|
||||
}
|
||||
|
||||
#endif // !SRC_NAPI_INL_DEPRECATED_H_
|
6936
c++/napi-inl.h
Normal file
6936
c++/napi-inl.h
Normal file
File diff suppressed because it is too large
Load Diff
3290
c++/napi.h
Normal file
3290
c++/napi.h
Normal file
File diff suppressed because it is too large
Load Diff
29
date.go
Normal file
29
date.go
Normal file
@ -0,0 +1,29 @@
|
||||
package napi
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type Date struct{ value }
|
||||
|
||||
// Convert [ValueType] to [*Date]
|
||||
func ToDate(o ValueType) *Date { return &Date{o} }
|
||||
|
||||
func CreateDate(env EnvType, date time.Time) (*Date, error) {
|
||||
value, err := mustValueErr(napi.CreateDate(env.NapiValue(), float64(date.UnixMilli())))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Date{value: &Value{env: env, valueOf: value}}, nil
|
||||
}
|
||||
|
||||
// Get time from [*Date] object.
|
||||
func (d Date) Time() (time.Time, error) {
|
||||
timeFloat, err := mustValueErr(napi.GetDateValue(d.NapiEnv(), d.NapiValue()))
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.UnixMilli(int64(timeFloat)), nil
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
"github.com/akshayganeshen/napi-go/entry"
|
||||
)
|
||||
|
||||
func init() {
|
||||
entry.Export("getPromise", GetPromiseHandler)
|
||||
}
|
||||
|
||||
func GetPromiseHandler(env napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
result, _ := napi.CreatePromise(env)
|
||||
asyncResourceName, _ := napi.CreateStringUtf8(
|
||||
env,
|
||||
"napi-go/async-promise-example",
|
||||
)
|
||||
|
||||
var asyncWork napi.AsyncWork
|
||||
asyncWork, _ = napi.CreateAsyncWork(
|
||||
env,
|
||||
nil, asyncResourceName,
|
||||
func(env napi.Env) {
|
||||
fmt.Printf("AsyncExecuteCallback(start)\n")
|
||||
defer fmt.Printf("AsyncExecuteCallback(stop)\n")
|
||||
time.Sleep(time.Second)
|
||||
},
|
||||
func(env napi.Env, status napi.Status) {
|
||||
defer napi.DeleteAsyncWork(env, asyncWork)
|
||||
|
||||
if status == napi.StatusCancelled {
|
||||
fmt.Printf("AsyncCompleteCallback(cancelled)\n")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("AsyncCompleteCallback\n")
|
||||
resolution, _ := napi.CreateStringUtf8(env, "resolved")
|
||||
napi.ResolveDeferred(env, result.Deferred, resolution)
|
||||
},
|
||||
)
|
||||
napi.QueueAsyncWork(env, asyncWork)
|
||||
|
||||
return result.Value
|
||||
}
|
||||
|
||||
func main() {}
|
@ -1,25 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
"github.com/akshayganeshen/napi-go/entry"
|
||||
)
|
||||
|
||||
func init() {
|
||||
entry.Export("getCallback", GetCallbackHandler)
|
||||
}
|
||||
|
||||
func GetCallbackHandler(env napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
result, _ := napi.CreateFunction(
|
||||
env,
|
||||
"callback",
|
||||
func(env napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
result, _ := napi.CreateStringUtf8(env, "hello world")
|
||||
return result
|
||||
},
|
||||
)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func main() {}
|
@ -1,52 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
"github.com/akshayganeshen/napi-go/entry"
|
||||
)
|
||||
|
||||
func init() {
|
||||
entry.Export("describeArgs", DescribeArgsHandler)
|
||||
}
|
||||
|
||||
func DescribeArgsHandler(env napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
extractedInfo, _ := napi.GetCbInfo(env, info)
|
||||
result, _ := napi.CreateArrayWithLength(env, len(extractedInfo.Args))
|
||||
for i, arg := range extractedInfo.Args {
|
||||
vt, _ := napi.Typeof(env, arg)
|
||||
dv, _ := napi.CreateStringUtf8(env, DescribeValueType(vt))
|
||||
napi.SetElement(env, result, i, dv)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func DescribeValueType(vt napi.ValueType) string {
|
||||
switch vt {
|
||||
case napi.ValueTypeUndefined:
|
||||
return "undefined"
|
||||
case napi.ValueTypeNull:
|
||||
return "null"
|
||||
case napi.ValueTypeBoolean:
|
||||
return "boolean"
|
||||
case napi.ValueTypeNumber:
|
||||
return "number"
|
||||
case napi.ValueTypeString:
|
||||
return "string"
|
||||
case napi.ValueTypeSymbol:
|
||||
return "symbol"
|
||||
case napi.ValueTypeObject:
|
||||
return "object"
|
||||
case napi.ValueTypeFunction:
|
||||
return "function"
|
||||
case napi.ValueTypeExternal:
|
||||
return "external"
|
||||
case napi.ValueTypeBigint:
|
||||
return "bigint"
|
||||
|
||||
default:
|
||||
return "other"
|
||||
}
|
||||
}
|
||||
|
||||
func main() {}
|
@ -1,19 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
"github.com/akshayganeshen/napi-go/entry"
|
||||
)
|
||||
|
||||
func init() {
|
||||
entry.Export("hello", HelloHandler)
|
||||
}
|
||||
|
||||
func HelloHandler(env napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
fmt.Println("hello world!")
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {}
|
@ -1,81 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
"github.com/akshayganeshen/napi-go/entry"
|
||||
"github.com/akshayganeshen/napi-go/js"
|
||||
)
|
||||
|
||||
func init() {
|
||||
entry.Export("getMap", GetMapHandler)
|
||||
entry.Export("getCallback", js.AsCallback(GetCallback))
|
||||
entry.Export("getArray", js.AsCallback(GetArray))
|
||||
entry.Export("getPromiseResolve", js.AsCallback(GetPromiseResolve))
|
||||
entry.Export("getPromiseReject", js.AsCallback(GetPromiseReject))
|
||||
}
|
||||
|
||||
func GetMapHandler(env napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
jsEnv := js.AsEnv(env)
|
||||
|
||||
return jsEnv.ValueOf(
|
||||
map[string]any{
|
||||
"string": "hello world",
|
||||
"number": 123,
|
||||
"bool": false,
|
||||
"undefined": jsEnv.Undefined(),
|
||||
"null": nil,
|
||||
"function": jsEnv.FuncOf(
|
||||
func(env js.Env, this js.Value, args []js.Value) any {
|
||||
return "hello world"
|
||||
},
|
||||
),
|
||||
},
|
||||
).Value
|
||||
}
|
||||
|
||||
func GetCallback(env js.Env, this js.Value, args []js.Value) any {
|
||||
return func(env js.Env, this js.Value, args []js.Value) any {
|
||||
return map[string]any{
|
||||
"this": this,
|
||||
"args": args,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetArray(env js.Env, this js.Value, args []js.Value) any {
|
||||
return []any{
|
||||
"hello world",
|
||||
123,
|
||||
true,
|
||||
map[string]any{
|
||||
"key": "value",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetPromiseResolve(env js.Env, this js.Value, args []js.Value) any {
|
||||
promise := env.NewPromise()
|
||||
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
promise.Resolve("resolved")
|
||||
}()
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
func GetPromiseReject(env js.Env, this js.Value, args []js.Value) any {
|
||||
promise := env.NewPromise()
|
||||
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
promise.Reject(fmt.Errorf("rejected"))
|
||||
}()
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
func main() {}
|
66
entry/entry.go
Normal file
66
entry/entry.go
Normal file
@ -0,0 +1,66 @@
|
||||
package entry
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DDEBUG
|
||||
#cgo CFLAGS: -D_DEBUG
|
||||
#cgo CFLAGS: -DV8_ENABLE_CHECKS
|
||||
#cgo CFLAGS: -DNAPI_EXPERIMENTAL
|
||||
#cgo CFLAGS: -I/usr/local/include/node
|
||||
#cgo CXXFLAGS: -std=c++11
|
||||
|
||||
#cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup
|
||||
#cgo darwin LDFLAGS: -Wl,-no_pie
|
||||
#cgo darwin LDFLAGS: -Wl,-search_paths_first
|
||||
#cgo (darwin && amd64) LDFLAGS: -arch x86_64
|
||||
#cgo (darwin && arm64) LDFLAGS: -arch arm64
|
||||
|
||||
#cgo linux LDFLAGS: -Wl,-unresolved-symbols=ignore-all
|
||||
|
||||
#cgo LDFLAGS: -L${SRCDIR}
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "./entry.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
gonapi "sirherobrine23.com.br/Sirherobrine23/napi-go"
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type registerCallback func(env napi.Env, object napi.Value)
|
||||
|
||||
var modFuncInit = []registerCallback{}
|
||||
|
||||
//export initializeModule
|
||||
func initializeModule(cEnv C.napi_env, cExports C.napi_value) C.napi_value {
|
||||
env, exports := napi.Env(cEnv), napi.Value(cExports)
|
||||
napi.InitializeInstanceData(env)
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch v := err.(type) {
|
||||
case error:
|
||||
gonapi.ThrowError(gonapi.N_APIEnv(env), "", v.Error())
|
||||
default:
|
||||
gonapi.ThrowError(gonapi.N_APIEnv(env), "", fmt.Sprintf("%s", v))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for _, registerCall := range modFuncInit {
|
||||
registerCall(env, exports)
|
||||
}
|
||||
|
||||
return cExports
|
||||
}
|
||||
|
||||
func Register(fn func(env gonapi.EnvType, export *gonapi.Object)) {
|
||||
modFuncInit = append(modFuncInit, func(env napi.Env, object napi.Value) {
|
||||
registerEnv := gonapi.N_APIEnv(env)
|
||||
registerObj := gonapi.ToObject(gonapi.N_APIValue(registerEnv, object))
|
||||
fn(registerEnv, registerObj)
|
||||
})
|
||||
}
|
@ -7,9 +7,9 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// InitializeModule is a N-API module initialization function.
|
||||
// InitializeModule is suitable for use as a napi_addon_register_func.
|
||||
extern napi_value InitializeModule(
|
||||
// initializeModule is a N-API module initialization function.
|
||||
// initializeModule is suitable for use as a napi_addon_register_func.
|
||||
extern napi_value initializeModule(
|
||||
napi_env env,
|
||||
napi_value exports
|
||||
);
|
||||
|
@ -1,19 +0,0 @@
|
||||
package entry
|
||||
|
||||
import (
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
)
|
||||
|
||||
type napiGoExport struct {
|
||||
Name string
|
||||
Callback napi.Callback
|
||||
}
|
||||
|
||||
var napiGoGlobalExports []napiGoExport
|
||||
|
||||
func Export(name string, callback napi.Callback) {
|
||||
napiGoGlobalExports = append(napiGoGlobalExports, napiGoExport{
|
||||
Name: name,
|
||||
Callback: callback,
|
||||
})
|
||||
}
|
@ -2,4 +2,4 @@
|
||||
|
||||
#include "./entry.h"
|
||||
|
||||
NAPI_MODULE(napiGo, InitializeModule)
|
||||
NAPI_MODULE(napiGo, initializeModule)
|
||||
|
@ -1,26 +0,0 @@
|
||||
package entry
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./entry.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
)
|
||||
|
||||
//export InitializeModule
|
||||
func InitializeModule(cEnv C.napi_env, cExports C.napi_value) C.napi_value {
|
||||
env, exports := napi.Env(cEnv), napi.Value(cExports)
|
||||
napi.InitializeInstanceData(env)
|
||||
|
||||
for _, export := range napiGoGlobalExports {
|
||||
cb, _ := napi.CreateFunction(env, export.Name, export.Callback)
|
||||
name, _ := napi.CreateStringUtf8(env, export.Name)
|
||||
napi.SetProperty(env, exports, name, cb)
|
||||
}
|
||||
|
||||
return cExports
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package entry
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DDEBUG
|
||||
#cgo CFLAGS: -D_DEBUG
|
||||
#cgo CFLAGS: -DV8_ENABLE_CHECKS
|
||||
#cgo CFLAGS: -DNAPI_EXPERIMENTAL
|
||||
#cgo CFLAGS: -I/usr/local/include/node
|
||||
#cgo CXXFLAGS: -std=c++11
|
||||
|
||||
#cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup
|
||||
#cgo darwin LDFLAGS: -Wl,-no_pie
|
||||
#cgo darwin LDFLAGS: -Wl,-search_paths_first
|
||||
#cgo darwin LDFLAGS: -arch x86_64
|
||||
|
||||
#cgo linux LDFLAGS: -Wl,-unresolved-symbols=ignore-all
|
||||
|
||||
#cgo LDFLAGS: -L${SRCDIR}
|
||||
#cgo LDFLAGS: -stdlib=libc++
|
||||
*/
|
||||
import "C"
|
37
error.go
Normal file
37
error.go
Normal file
@ -0,0 +1,37 @@
|
||||
package napi
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type Error struct{ value }
|
||||
|
||||
func ToError(o ValueType) *Error { return &Error{o} }
|
||||
|
||||
func CreateError(env EnvType, msg string) (*Error, error) {
|
||||
napiMsg, err := CreateString(env, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
napiValue, err := mustValueErr(napi.CreateError(env.NapiValue(), nil, napiMsg.NapiValue()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToError(N_APIValue(env, napiValue)), nil
|
||||
}
|
||||
|
||||
func (er *Error) ThrowAsJavaScriptException() error {
|
||||
return singleMustValueErr(napi.Throw(er.NapiEnv(), er.NapiValue()))
|
||||
}
|
||||
|
||||
// This throws a JavaScript Error with the text provided.
|
||||
func ThrowError(env EnvType, code, err string) error {
|
||||
if code == "" {
|
||||
stackTraceBuf := make([]byte, 8192)
|
||||
stackTraceSz := runtime.Stack(stackTraceBuf, false)
|
||||
code = string(stackTraceBuf[:stackTraceSz])
|
||||
}
|
||||
return singleMustValueErr(napi.ThrowError(env.NapiValue(), code, err))
|
||||
}
|
80
example/test.go
Normal file
80
example/test.go
Normal file
@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/netip"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go"
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/entry"
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/js"
|
||||
)
|
||||
|
||||
type Test struct {
|
||||
Int int
|
||||
String string
|
||||
Sub []any
|
||||
}
|
||||
|
||||
func init() {
|
||||
entry.Register(func(env napi.EnvType, export *napi.Object) {
|
||||
inNode, _ := napi.CreateString(env, "from golang napi string")
|
||||
inNode2, _ := napi.CopyBuffer(env, []byte{1, 0, 244, 21})
|
||||
toGoReflect := &Test{
|
||||
Int: 14,
|
||||
String: "From golang",
|
||||
Sub: []any{
|
||||
1,
|
||||
[]string{"test", "gopher"},
|
||||
[]bool{false, true},
|
||||
[]int{23, 244, 10, 2024, 2025, 2000},
|
||||
map[string]string{"exampleMap": "test"},
|
||||
map[int]string{1: "one"},
|
||||
map[bool]string{false: "false", true: "true"},
|
||||
map[[2]string]string{[2]string{"go"}: "example"},
|
||||
netip.IPv4Unspecified(),
|
||||
netip.IPv6Unspecified(),
|
||||
netip.AddrPortFrom(netip.IPv6Unspecified(), 19132),
|
||||
nil,
|
||||
true,
|
||||
false,
|
||||
inNode,
|
||||
inNode2,
|
||||
func() {
|
||||
println("called in go")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
napiStruct, err := js.ValueOf(env, toGoReflect)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
export.Set("goStruct", napiStruct)
|
||||
|
||||
fnCall, err := js.GoFuncOf(env, func(call ...any) (string, error) {
|
||||
d, err := json.MarshalIndent(call, "", " ")
|
||||
if err == nil {
|
||||
println(string(d))
|
||||
}
|
||||
return string(d), err
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
export.Set("printAny", fnCall)
|
||||
|
||||
fnCallStruct, err := js.GoFuncOf(env, func(call ...Test) (string, error) {
|
||||
d, err := json.MarshalIndent(call, "", " ")
|
||||
if err == nil {
|
||||
println(string(d))
|
||||
}
|
||||
return string(d), err
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
export.Set("printTestStruct", fnCallStruct)
|
||||
})
|
||||
}
|
||||
|
||||
func main() {}
|
96
function.go
Normal file
96
function.go
Normal file
@ -0,0 +1,96 @@
|
||||
package napi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type Function struct{ value }
|
||||
|
||||
// Function to call on Javascript caller
|
||||
type Callback func(env EnvType, this ValueType, args []ValueType) (ValueType, error)
|
||||
|
||||
// Convert [ValueType] to [*Function]
|
||||
func ToFunction(o ValueType) *Function { return &Function{o} }
|
||||
|
||||
func CreateFunction(env EnvType, name string, callback Callback) (*Function, error) {
|
||||
return CreateFunctionNapi(env, name, func(napiEnv napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
env := N_APIEnv(napiEnv)
|
||||
cbInfo, err := mustValueErr(napi.GetCbInfo(napiEnv, info))
|
||||
if err != nil {
|
||||
ThrowError(env, "", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
this := N_APIValue(env, cbInfo.This)
|
||||
args := make([]ValueType, len(cbInfo.Args))
|
||||
for i, cbArg := range cbInfo.Args {
|
||||
args[i] = N_APIValue(env, cbArg)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch v := err.(type) {
|
||||
case error:
|
||||
ThrowError(env, "", v.Error())
|
||||
default:
|
||||
ThrowError(env, "", fmt.Sprintf("panic recover: %s", err))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
res, err := callback(env, this, args)
|
||||
switch {
|
||||
case err != nil:
|
||||
ThrowError(env, "", err.Error())
|
||||
return nil
|
||||
case res == nil:
|
||||
und, _ := env.Undefined()
|
||||
return und.NapiValue()
|
||||
default:
|
||||
typeOf, _ := res.Type()
|
||||
if typeOf == TypeError {
|
||||
ToError(res).ThrowAsJavaScriptException()
|
||||
return nil
|
||||
}
|
||||
return res.NapiValue()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func CreateFunctionNapi(env EnvType, name string, callback napi.Callback) (*Function, error) {
|
||||
fnCall, err := mustValueErr(napi.CreateFunction(env.NapiValue(), name, callback))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToFunction(N_APIValue(env, fnCall)), nil
|
||||
}
|
||||
|
||||
func (fn *Function) internalCall(this napi.Value, argc int, argv []napi.Value) (ValueType, error) {
|
||||
// napi_call_function(env, global, add_two, argc, argv, &return_val);
|
||||
res, err := mustValueErr(napi.CallFunction(fn.NapiEnv(), this, fn.NapiValue(), argc, argv))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return N_APIValue(fn.Env(), res), nil
|
||||
}
|
||||
|
||||
// Call function with custom global/this value
|
||||
func (fn *Function) CallWithGlobal(this ValueType, args ...ValueType) (ValueType, error) {
|
||||
argc := len(args)
|
||||
argv := make([]napi.Value, argc)
|
||||
for index := range argc {
|
||||
argv[index] = args[index].NapiValue()
|
||||
}
|
||||
return fn.internalCall(this.NapiValue(), argc, argv)
|
||||
}
|
||||
|
||||
// Call function with args
|
||||
func (fn *Function) Call(args ...ValueType) (ValueType, error) {
|
||||
global, err := fn.Env().Global()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fn.CallWithGlobal(global, args...)
|
||||
}
|
4
go.mod
4
go.mod
@ -1,3 +1,3 @@
|
||||
module github.com/akshayganeshen/napi-go
|
||||
module sirherobrine23.com.br/Sirherobrine23/napi-go
|
||||
|
||||
go 1.18
|
||||
go 1.24
|
||||
|
1294
internal/napi/js_native_api.go
Normal file
1294
internal/napi/js_native_api.go
Normal file
File diff suppressed because it is too large
Load Diff
34
internal/napi/key_type.go
Normal file
34
internal/napi/key_type.go
Normal file
@ -0,0 +1,34 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// KeyCollectionMode type
|
||||
type KeyCollectionMode C.napi_key_collection_mode
|
||||
|
||||
const (
|
||||
KeyIncludePrototypes KeyCollectionMode = C.napi_key_include_prototypes
|
||||
KeyOwnOnly KeyCollectionMode = C.napi_key_own_only
|
||||
)
|
||||
|
||||
// KeyFilter type
|
||||
type KeyFilter C.napi_key_filter
|
||||
|
||||
const (
|
||||
KeyAllProperties KeyFilter = C.napi_key_all_properties
|
||||
KeyWritable KeyFilter = C.napi_key_writable
|
||||
KeyEnumerable KeyFilter = C.napi_key_enumerable
|
||||
KeyConfigurable KeyFilter = C.napi_key_configurable
|
||||
KeySkipStrings KeyFilter = C.napi_key_skip_strings
|
||||
KeySkipSymbols KeyFilter = C.napi_key_skip_symbols
|
||||
)
|
||||
|
||||
// KeyConversion type
|
||||
type KeyConversion C.napi_key_conversion
|
||||
|
||||
const (
|
||||
KeyKeepNumbers KeyConversion = C.napi_key_keep_numbers
|
||||
KeyNumbersToStrings KeyConversion = C.napi_key_numbers_to_strings
|
||||
)
|
@ -11,11 +11,11 @@ package napi
|
||||
#cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup
|
||||
#cgo darwin LDFLAGS: -Wl,-no_pie
|
||||
#cgo darwin LDFLAGS: -Wl,-search_paths_first
|
||||
#cgo darwin LDFLAGS: -arch x86_64
|
||||
// #cgo darwin amd64 LDFLAGS: -arch x86_64
|
||||
// #cgo darwin arm64 LDFLAGS: -arch arm64
|
||||
|
||||
#cgo linux LDFLAGS: -Wl,-unresolved-symbols=ignore-all
|
||||
|
||||
#cgo LDFLAGS: -L${SRCDIR}
|
||||
#cgo LDFLAGS: -stdlib=libc++
|
||||
*/
|
||||
import "C"
|
||||
import "C"
|
@ -1,6 +1,7 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
@ -113,11 +114,12 @@ func CreateThreadsafeFunction(
|
||||
|
||||
func CallThreadsafeFunction(
|
||||
fn ThreadsafeFunction,
|
||||
mode ThreadsafeFunctionCallMode,
|
||||
) Status {
|
||||
return Status(C.napi_call_threadsafe_function(
|
||||
C.napi_threadsafe_function(fn),
|
||||
nil,
|
||||
C.napi_tsfn_blocking,
|
||||
C.napi_threadsafe_function_call_mode(mode),
|
||||
))
|
||||
}
|
||||
|
||||
@ -129,9 +131,108 @@ func AcquireThreadsafeFunction(fn ThreadsafeFunction) Status {
|
||||
|
||||
func ReleaseThreadsafeFunction(
|
||||
fn ThreadsafeFunction,
|
||||
mode ThreadsafeFunctionReleaseMode,
|
||||
) Status {
|
||||
return Status(C.napi_release_threadsafe_function(
|
||||
C.napi_threadsafe_function(fn),
|
||||
C.napi_tsfn_release,
|
||||
C.napi_threadsafe_function_release_mode(mode),
|
||||
))
|
||||
}
|
||||
|
||||
func GetThreadsafeFunctionContext(
|
||||
fn ThreadsafeFunction,
|
||||
) (unsafe.Pointer, Status) {
|
||||
var context unsafe.Pointer
|
||||
status := Status(C.napi_get_threadsafe_function_context(
|
||||
C.napi_threadsafe_function(fn),
|
||||
&context,
|
||||
))
|
||||
return context, status
|
||||
}
|
||||
|
||||
func RefThreadsafeFunction(env Env, fn ThreadsafeFunction) Status {
|
||||
return Status(C.napi_ref_threadsafe_function(
|
||||
C.napi_env(env),
|
||||
C.napi_threadsafe_function(fn),
|
||||
))
|
||||
}
|
||||
|
||||
func UnrefThreadsafeFunction(env Env, fn ThreadsafeFunction) Status {
|
||||
return Status(C.napi_unref_threadsafe_function(
|
||||
C.napi_env(env),
|
||||
C.napi_threadsafe_function(fn),
|
||||
))
|
||||
}
|
||||
|
||||
func ThrowSyntaxError(env Env, code, msg string) Status {
|
||||
codeCStr, msgCStr := C.CString(code), C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(codeCStr))
|
||||
defer C.free(unsafe.Pointer(msgCStr))
|
||||
|
||||
return Status(C.node_api_throw_syntax_error(
|
||||
C.napi_env(env),
|
||||
codeCStr,
|
||||
msgCStr,
|
||||
))
|
||||
}
|
||||
|
||||
func CreateSyntaxError(env Env, code, msg Value) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.node_api_create_syntax_error(
|
||||
C.napi_env(env),
|
||||
C.napi_value(code),
|
||||
C.napi_value(msg),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func SymbolFor(env Env, description string) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.node_api_symbol_for(
|
||||
C.napi_env(env),
|
||||
C.CString(description),
|
||||
C.size_t(len(description)),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreatePropertyKeyLatin1(env Env, str string) (Value, Status) {
|
||||
cstr := C.CString(str)
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
|
||||
var result Value
|
||||
status := Status(C.node_api_create_property_key_latin1(
|
||||
C.napi_env(env),
|
||||
cstr,
|
||||
C.size_t(len([]byte(str))),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreatePropertyKeyUtf16(env Env, str []uint16) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.node_api_create_property_key_utf16(
|
||||
C.napi_env(env),
|
||||
(*C.char16_t)(unsafe.Pointer(&str[0])),
|
||||
C.size_t(len(str)),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreatePropertyKeyUtf8(env Env, str string) (Value, Status) {
|
||||
cstr := C.CString(str)
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
|
||||
var result Value
|
||||
status := Status(C.node_api_create_property_key_utf8(
|
||||
C.napi_env(env),
|
||||
cstr,
|
||||
C.size_t(len([]byte(str))),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
18
internal/napi/property_attrib_type.go
Normal file
18
internal/napi/property_attrib_type.go
Normal file
@ -0,0 +1,18 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type PropertyAttributes C.napi_property_attributes
|
||||
|
||||
const (
|
||||
Default PropertyAttributes = C.napi_default
|
||||
Writable PropertyAttributes = C.napi_writable
|
||||
Enumerable PropertyAttributes = C.napi_enumerable
|
||||
Configurable PropertyAttributes = C.napi_configurable
|
||||
Static PropertyAttributes = C.napi_static
|
||||
DefaultMethod PropertyAttributes = C.napi_default_method
|
||||
DefaultJSProperty PropertyAttributes = C.napi_default_jsproperty
|
||||
)
|
20
internal/napi/threadsafe_function_type.go
Normal file
20
internal/napi/threadsafe_function_type.go
Normal file
@ -0,0 +1,20 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type ThreadsafeFunctionReleaseMode C.napi_threadsafe_function_release_mode
|
||||
|
||||
const (
|
||||
Release ThreadsafeFunctionReleaseMode = C.napi_tsfn_release
|
||||
Abort ThreadsafeFunctionReleaseMode = C.napi_tsfn_abort
|
||||
)
|
||||
|
||||
type ThreadsafeFunctionCallMode C.napi_threadsafe_function_call_mode
|
||||
|
||||
const (
|
||||
NonBlocking ThreadsafeFunctionCallMode = C.napi_tsfn_nonblocking
|
||||
Blocking ThreadsafeFunctionCallMode = C.napi_tsfn_blocking
|
||||
)
|
22
internal/napi/typed_array_type.go
Normal file
22
internal/napi/typed_array_type.go
Normal file
@ -0,0 +1,22 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type TypedArrayType C.napi_typedarray_type
|
||||
|
||||
const (
|
||||
TypedArrayInt8Array TypedArrayType = C.napi_int8_array
|
||||
TypedArrayUint8Array TypedArrayType = C.napi_uint8_array
|
||||
TypedArrayUint8ClampedArray TypedArrayType = C.napi_uint8_clamped_array
|
||||
TypedArrayInt16Array TypedArrayType = C.napi_int16_array
|
||||
TypedArrayUint16Array TypedArrayType = C.napi_uint16_array
|
||||
TypedArrayInt32Array TypedArrayType = C.napi_int32_array
|
||||
TypedArrayUint32Array TypedArrayType = C.napi_uint32_array
|
||||
TypedArrayFloat32Array TypedArrayType = C.napi_float32_array
|
||||
TypedArrayFloat64Array TypedArrayType = C.napi_float64_array
|
||||
TypedArrayBigInt64Array TypedArrayType = C.napi_bigint64_array
|
||||
TypedArrayBigUint64Array TypedArrayType = C.napi_biguint64_array
|
||||
)
|
41
internal/napi/types.go
Normal file
41
internal/napi/types.go
Normal file
@ -0,0 +1,41 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
type PropertyDescriptor struct {
|
||||
Utf8name string
|
||||
Name Value
|
||||
Method Callback
|
||||
Getter Callback
|
||||
Setter Callback
|
||||
Value Value
|
||||
Attributes PropertyAttributes
|
||||
Data unsafe.Pointer
|
||||
}
|
||||
|
||||
type Finalize func(env Env, finalizeData, finalizeHint unsafe.Pointer)
|
||||
|
||||
func FinalizeToFinalizer(fn Finalize) Finalizer {
|
||||
return func(env C.napi_env, finalizeData, finalizeHint unsafe.Pointer) {
|
||||
fn(Env(env), finalizeData, finalizeHint)
|
||||
}
|
||||
}
|
||||
|
||||
// Finalizer as a C-compatible function pointer type
|
||||
type Finalizer func(env C.napi_env, finalizeData, finalizeHint unsafe.Pointer)
|
||||
|
||||
type Reference struct {
|
||||
Ref unsafe.Pointer
|
||||
}
|
||||
|
||||
type EscapableHandleScope struct {
|
||||
Scope unsafe.Pointer
|
||||
}
|
||||
|
||||
type HandleScope struct {
|
||||
Scope unsafe.Pointer
|
||||
}
|
48
internal/napi/value_type.go
Normal file
48
internal/napi/value_type.go
Normal file
@ -0,0 +1,48 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type ValueType C.napi_valuetype
|
||||
|
||||
const (
|
||||
ValueTypeUndefined ValueType = C.napi_undefined
|
||||
ValueTypeNull ValueType = C.napi_null
|
||||
ValueTypeBoolean ValueType = C.napi_boolean
|
||||
ValueTypeNumber ValueType = C.napi_number
|
||||
ValueTypeString ValueType = C.napi_string
|
||||
ValueTypeSymbol ValueType = C.napi_symbol
|
||||
ValueTypeObject ValueType = C.napi_object
|
||||
ValueTypeFunction ValueType = C.napi_function
|
||||
ValueTypeExternal ValueType = C.napi_external
|
||||
ValueTypeBigint ValueType = C.napi_bigint
|
||||
)
|
||||
|
||||
func (v ValueType) String() string {
|
||||
switch v {
|
||||
case ValueTypeUndefined:
|
||||
return "undefined"
|
||||
case ValueTypeNull:
|
||||
return "null"
|
||||
case ValueTypeBoolean:
|
||||
return "boolean"
|
||||
case ValueTypeNumber:
|
||||
return "number"
|
||||
case ValueTypeString:
|
||||
return "string"
|
||||
case ValueTypeSymbol:
|
||||
return "symbol"
|
||||
case ValueTypeObject:
|
||||
return "object"
|
||||
case ValueTypeFunction:
|
||||
return "function"
|
||||
case ValueTypeExternal:
|
||||
return "external"
|
||||
case ValueTypeBigint:
|
||||
return "bigint"
|
||||
default:
|
||||
return "undefined"
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package js
|
||||
|
||||
import (
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
)
|
||||
|
||||
type Callback = func(env Env, this Value, args []Value) any
|
||||
|
||||
func AsCallback(fn Callback) napi.Callback {
|
||||
return func(env napi.Env, info napi.CallbackInfo) napi.Value {
|
||||
cbInfo, st := napi.GetCbInfo(env, info)
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
|
||||
jsEnv := AsEnv(env)
|
||||
this := Value{
|
||||
Env: jsEnv,
|
||||
Value: cbInfo.This,
|
||||
}
|
||||
args := make([]Value, len(cbInfo.Args))
|
||||
for i, cbArg := range cbInfo.Args {
|
||||
args[i] = Value{
|
||||
Env: jsEnv,
|
||||
Value: cbArg,
|
||||
}
|
||||
}
|
||||
|
||||
result := fn(jsEnv, this, args)
|
||||
return jsEnv.ValueOf(result).Value
|
||||
}
|
||||
}
|
196
js/env.go
196
js/env.go
@ -1,196 +0,0 @@
|
||||
package js
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
)
|
||||
|
||||
type Env struct {
|
||||
Env napi.Env
|
||||
}
|
||||
|
||||
type InvalidValueTypeError struct {
|
||||
Value any
|
||||
}
|
||||
|
||||
var _ error = InvalidValueTypeError{}
|
||||
|
||||
func AsEnv(env napi.Env) Env {
|
||||
return Env{
|
||||
Env: env,
|
||||
}
|
||||
}
|
||||
|
||||
func (e Env) Global() Value {
|
||||
v, st := napi.GetGlobal(e.Env)
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
return Value{
|
||||
Env: e,
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
|
||||
func (e Env) Null() Value {
|
||||
v, st := napi.GetNull(e.Env)
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
return Value{
|
||||
Env: e,
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
|
||||
func (e Env) Undefined() Value {
|
||||
v, st := napi.GetUndefined(e.Env)
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
return Value{
|
||||
Env: e,
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
|
||||
func (e Env) ValueOf(x any) Value {
|
||||
var (
|
||||
v napi.Value
|
||||
st napi.Status
|
||||
)
|
||||
|
||||
switch xt := x.(type) {
|
||||
case Value:
|
||||
return xt
|
||||
case []Value:
|
||||
l := len(xt)
|
||||
v, st = napi.CreateArrayWithLength(e.Env, l)
|
||||
if st != napi.StatusOK {
|
||||
break
|
||||
}
|
||||
|
||||
for i, xti := range xt {
|
||||
// TODO: Use Value.SetIndex helper
|
||||
st = napi.SetElement(e.Env, v, i, xti.Value)
|
||||
if st != napi.StatusOK {
|
||||
break
|
||||
}
|
||||
}
|
||||
case Func:
|
||||
return xt.Value
|
||||
case Callback:
|
||||
return e.FuncOf(xt).Value
|
||||
case *Promise:
|
||||
v, st = xt.Promise.Value, napi.StatusOK
|
||||
case napi.Value:
|
||||
v, st = xt, napi.StatusOK
|
||||
|
||||
case nil:
|
||||
v, st = napi.GetNull(e.Env)
|
||||
case bool:
|
||||
v, st = napi.GetBoolean(e.Env, xt)
|
||||
case int:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case int8:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case int16:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case int64:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case uint:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case uint8:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case uint16:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case uint64:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case uintptr:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case unsafe.Pointer:
|
||||
v, st = napi.CreateDouble(e.Env, float64(uintptr(xt)))
|
||||
case float32:
|
||||
v, st = napi.CreateDouble(e.Env, float64(xt))
|
||||
case float64:
|
||||
v, st = napi.CreateDouble(e.Env, xt)
|
||||
case string:
|
||||
v, st = napi.CreateStringUtf8(e.Env, xt)
|
||||
case error:
|
||||
msg := e.ValueOf(xt.Error())
|
||||
v, st = napi.CreateError(e.Env, nil, msg.Value)
|
||||
case []any:
|
||||
l := len(xt)
|
||||
v, st = napi.CreateArrayWithLength(e.Env, l)
|
||||
if st != napi.StatusOK {
|
||||
break
|
||||
}
|
||||
|
||||
for i, xti := range xt {
|
||||
// TODO: Use Value.SetIndex helper
|
||||
vti := e.ValueOf(xti)
|
||||
st = napi.SetElement(e.Env, v, i, vti.Value)
|
||||
if st != napi.StatusOK {
|
||||
break
|
||||
}
|
||||
}
|
||||
case map[string]any:
|
||||
v, st = napi.CreateObject(e.Env)
|
||||
if st != napi.StatusOK {
|
||||
break
|
||||
}
|
||||
|
||||
for xtk, xtv := range xt {
|
||||
// TODO: Use Value.Set helper
|
||||
vtk, vtv := e.ValueOf(xtk), e.ValueOf(xtv)
|
||||
st = napi.SetProperty(e.Env, v, vtk.Value, vtv.Value)
|
||||
if st != napi.StatusOK {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
panic(InvalidValueTypeError{x})
|
||||
}
|
||||
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
|
||||
return Value{
|
||||
Env: e,
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
|
||||
func (e Env) FuncOf(fn Callback) Func {
|
||||
// TODO: Add CreateReference to FuncOf to keep value alive
|
||||
v, st := napi.CreateFunction(
|
||||
e.Env,
|
||||
"",
|
||||
AsCallback(fn),
|
||||
)
|
||||
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
|
||||
return Func{
|
||||
Value: Value{
|
||||
Env: e,
|
||||
Value: v,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (e Env) NewPromise() *Promise {
|
||||
var result Promise
|
||||
result.reset(e)
|
||||
return &result
|
||||
}
|
||||
|
||||
func (err InvalidValueTypeError) Error() string {
|
||||
return fmt.Sprintf("Value cannot be represented in JS: %T", err.Value)
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package js
|
||||
|
||||
type Func struct {
|
||||
Value
|
||||
}
|
21
js/funcof.md
Normal file
21
js/funcof.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Go functions conversion to Javascript functions
|
||||
|
||||
## Simples conversions
|
||||
|
||||
| Go | Node |
|
||||
| --------------------------------- | ------------------------------------------- |
|
||||
| `func()` | `function(): void` |
|
||||
| `func() value` | `function(): value` |
|
||||
| `func(value1, value2)` | `function(value1, value2): void` |
|
||||
| `func() (value1, value2)` | `function(): [value1, value2]` |
|
||||
| `func(value1, value2, values...)` | `function(value1, value2, ...values): void` |
|
||||
| `func(values...)` | `function(...values): void` |
|
||||
|
||||
## Error throw
|
||||
|
||||
| Go | Node |
|
||||
| ------------------------------------------ | --------------------------------------------------- |
|
||||
| `func() error` | `function(): throw Error` |
|
||||
| `func(value1, value2) error` | `function(value1, value2): throw Error` |
|
||||
| `func() (value, error)` | `function(): value \|\| throw Error` |
|
||||
| `func(value1, value2) (...nValues, error)` | `function(value1, value2): (Array \|\|throw Error)` |
|
575
js/js.go
Normal file
575
js/js.go
Normal file
@ -0,0 +1,575 @@
|
||||
package js
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go"
|
||||
)
|
||||
|
||||
const propertiesTagName = "napi"
|
||||
|
||||
// Convert go types to valid NAPI, if not conpatible return Undefined.
|
||||
func ValueOf(env napi.EnvType, value any) (napiValue napi.ValueType, err error) {
|
||||
return valueOf(env, reflect.ValueOf(value))
|
||||
}
|
||||
|
||||
// Convert NAPI value to Go values
|
||||
func ValueFrom(napiValue napi.ValueType, v any) error {
|
||||
ptr := reflect.ValueOf(v)
|
||||
if ptr.Kind() != reflect.Pointer {
|
||||
return fmt.Errorf("require point to convert napi value to go value")
|
||||
}
|
||||
return valueFrom(napiValue, ptr.Elem())
|
||||
}
|
||||
|
||||
func valueOf(env napi.EnvType, ptr reflect.Value) (napiValue napi.ValueType, err error) {
|
||||
defer func(err *error) {
|
||||
if err2 := recover(); err2 != nil {
|
||||
switch v := err2.(type) {
|
||||
case error:
|
||||
*err = v
|
||||
default:
|
||||
*err = fmt.Errorf("panic recover: %s", err2)
|
||||
}
|
||||
}
|
||||
}(&err)
|
||||
|
||||
if !ptr.IsValid() || ptr.IsZero() {
|
||||
return env.Undefined()
|
||||
}
|
||||
|
||||
// Marshalers
|
||||
if ptr.CanInterface() {
|
||||
switch v := ptr.Interface().(type) {
|
||||
case napi.ValueType:
|
||||
return v, nil
|
||||
case time.Time:
|
||||
return napi.CreateDate(env, v)
|
||||
case encoding.TextMarshaler:
|
||||
data, err := v.MarshalText()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return napi.CreateString(env, string(data))
|
||||
case json.Marshaler:
|
||||
var pointData any
|
||||
data, err := v.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if err = json.Unmarshal(data, &pointData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ValueOf(env, pointData)
|
||||
}
|
||||
}
|
||||
|
||||
ptrType := ptr.Type()
|
||||
switch ptrType.Kind() {
|
||||
case reflect.Pointer:
|
||||
return valueOf(env, ptr.Elem())
|
||||
case reflect.String:
|
||||
return napi.CreateString(env, ptr.String())
|
||||
case reflect.Bool:
|
||||
return napi.CreateBoolean(env, ptr.Bool())
|
||||
case reflect.Int, reflect.Uint, reflect.Int32, reflect.Uint32, reflect.Float32, reflect.Int8, reflect.Uint8, reflect.Int16, reflect.Uint16:
|
||||
return napi.CreateNumber(env, ptr.Int())
|
||||
case reflect.Float64:
|
||||
return napi.CreateNumber(env, ptr.Float())
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
return napi.CreateBigint(env, ptr.Int())
|
||||
case reflect.Func:
|
||||
return funcOf(env, ptr)
|
||||
case reflect.Slice, reflect.Array:
|
||||
arr, err := napi.CreateArray(env, ptr.Len())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for index := range ptr.Len() {
|
||||
value, err := valueOf(env, ptr.Index(index))
|
||||
if err != nil {
|
||||
return arr, err
|
||||
} else if err = arr.Set(index, value); err != nil {
|
||||
return arr, err
|
||||
}
|
||||
}
|
||||
return arr, nil
|
||||
case reflect.Struct:
|
||||
obj, err := napi.CreateObject(env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for keyIndex := range ptrType.NumField() {
|
||||
field, fieldType := ptr.Field(keyIndex), ptrType.Field(keyIndex)
|
||||
if !fieldType.IsExported() || fieldType.Tag.Get(propertiesTagName) == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
value, err := valueOf(env, field)
|
||||
if err != nil {
|
||||
return obj, err
|
||||
}
|
||||
|
||||
typeof, err := value.Type()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyNamed := fieldType.Name
|
||||
if strings.Count(fieldType.Tag.Get(propertiesTagName), ",") > 0 {
|
||||
fields := strings.SplitN(fieldType.Tag.Get(propertiesTagName), ",", 2)
|
||||
keyNamed = fields[0]
|
||||
switch fields[1] {
|
||||
case "omitempty":
|
||||
switch typeof {
|
||||
case napi.TypeUndefined, napi.TypeNull, napi.TypeUnkown:
|
||||
continue
|
||||
case napi.TypeString:
|
||||
str, err := napi.ToString(value).Utf8Value()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if str == "" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
case "omitzero":
|
||||
switch typeof {
|
||||
case napi.TypeUndefined, napi.TypeNull, napi.TypeUnkown:
|
||||
continue
|
||||
case napi.TypeDate:
|
||||
value, err := napi.ToDate(value).Time()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if value.Unix() == 0 {
|
||||
continue
|
||||
}
|
||||
case napi.TypeBigInt:
|
||||
value, err := napi.ToBigint(value).Int64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if value == 0 {
|
||||
continue
|
||||
}
|
||||
case napi.TypeNumber:
|
||||
value, err := napi.ToNumber(value).Int()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if value == 0 {
|
||||
continue
|
||||
}
|
||||
case napi.TypeArray:
|
||||
value, err := napi.ToArray(value).Length()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if value == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err = obj.Set(keyNamed, value); err != nil {
|
||||
return obj, err
|
||||
}
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
case reflect.Map:
|
||||
obj, err := napi.CreateObject(env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for ptrKey, ptrValue := range ptr.Seq2() {
|
||||
key, err := valueOf(env, ptrKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value, err := valueOf(env, ptrValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if err = obj.SetWithValue(key, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return obj, nil
|
||||
case reflect.Interface:
|
||||
if ptr.IsValid() {
|
||||
if ptr.IsNil() {
|
||||
return env.Null()
|
||||
} else if ptr.CanInterface() {
|
||||
return valueOf(env, reflect.ValueOf(ptr.Interface()))
|
||||
}
|
||||
}
|
||||
}
|
||||
return env.Undefined()
|
||||
}
|
||||
|
||||
func valueFrom(napiValue napi.ValueType, ptr reflect.Value) error {
|
||||
typeOf, err := napiValue.Type()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ptrType := ptr.Type()
|
||||
switch ptrType.Kind() {
|
||||
case reflect.Pointer:
|
||||
return valueFrom(napiValue, ptr.Elem())
|
||||
case reflect.Interface:
|
||||
// Check if is any and can set
|
||||
if ptr.CanSet() && ptrType == reflect.TypeFor[any]() {
|
||||
switch typeOf {
|
||||
case napi.TypeNull, napi.TypeUndefined, napi.TypeUnkown:
|
||||
ptr.Set(reflect.Zero(ptrType))
|
||||
return nil
|
||||
case napi.TypeBoolean:
|
||||
valueOf, err := napi.ToBoolean(napiValue).Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.Set(reflect.ValueOf(valueOf))
|
||||
case napi.TypeNumber:
|
||||
numberValue, err := napi.ToNumber(napiValue).Float()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.Set(reflect.ValueOf(numberValue))
|
||||
case napi.TypeBigInt:
|
||||
numberValue, err := napi.ToBigint(napiValue).Int64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.Set(reflect.ValueOf(numberValue))
|
||||
case napi.TypeString:
|
||||
str, err := napi.ToString(napiValue).Utf8Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.Set(reflect.ValueOf(str))
|
||||
case napi.TypeDate:
|
||||
timeDate, err := napi.ToDate(napiValue).Time()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.Set(reflect.ValueOf(timeDate))
|
||||
case napi.TypeArray:
|
||||
napiArray := napi.ToArray(napiValue)
|
||||
size, err := napiArray.Length()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value := reflect.MakeSlice(reflect.SliceOf(ptrType), size, size)
|
||||
for index := range size {
|
||||
napiValue, err := napiArray.Get(index)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if err = valueFrom(napiValue, value.Index(index)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ptr.Set(value)
|
||||
case napi.TypeBuffer:
|
||||
buff, err := napi.ToBuffer(napiValue).Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.Set(reflect.ValueOf(buff))
|
||||
case napi.TypeObject:
|
||||
obj := napi.ToObject(napiValue)
|
||||
goMap := reflect.MakeMap(reflect.MapOf(reflect.TypeFor[string](), reflect.TypeFor[any]()))
|
||||
for keyName, value := range obj.Seq() {
|
||||
valueOf := reflect.New(reflect.TypeFor[any]())
|
||||
if err := valueFrom(value, valueOf); err != nil {
|
||||
return err
|
||||
}
|
||||
goMap.SetMapIndex(reflect.ValueOf(keyName), valueOf)
|
||||
}
|
||||
ptr.Set(goMap)
|
||||
case napi.TypeFunction:
|
||||
ptr.Set(reflect.ValueOf(napi.ToFunction(napiValue)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("cannot set value, returned %s", typeOf)
|
||||
}
|
||||
|
||||
switch typeOf {
|
||||
case napi.TypeNull, napi.TypeUndefined, napi.TypeUnkown:
|
||||
switch ptrType.Kind() {
|
||||
case reflect.Interface, reflect.Pointer:
|
||||
ptr.Set(reflect.Zero(ptrType))
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot set value, returned %s", typeOf)
|
||||
}
|
||||
case napi.TypeBoolean:
|
||||
switch ptr.Kind() {
|
||||
case reflect.Bool:
|
||||
valueOf, err := napi.ToBoolean(napiValue).Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.SetBool(valueOf)
|
||||
default:
|
||||
return fmt.Errorf("cannot set boolean value to %s", ptr.Kind())
|
||||
}
|
||||
case napi.TypeNumber:
|
||||
switch ptrType.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
floatValue, err := napi.ToNumber(napiValue).Float()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.SetFloat(floatValue)
|
||||
return nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
numberValue, err := napi.ToNumber(napiValue).Int()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.SetInt(numberValue)
|
||||
return nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
numberValue, err := napi.ToNumber(napiValue).Int()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.SetUint(uint64(numberValue))
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot set number value to %s", ptr.Kind())
|
||||
}
|
||||
case napi.TypeBigInt:
|
||||
switch ptrType.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
numberValue, err := napi.ToNumber(napiValue).Int()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.SetInt(numberValue)
|
||||
return nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
numberValue, err := napi.ToNumber(napiValue).Int()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.SetUint(uint64(numberValue))
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot set number value to %s", ptr.Kind())
|
||||
}
|
||||
case napi.TypeString:
|
||||
switch ptr.Kind() {
|
||||
case reflect.String:
|
||||
default:
|
||||
return fmt.Errorf("cannot set string to %s", ptr.Kind())
|
||||
}
|
||||
str, err := napi.ToString(napiValue).Utf8Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.Set(reflect.ValueOf(str))
|
||||
return nil
|
||||
case napi.TypeDate:
|
||||
switch ptrType.Kind() {
|
||||
case reflect.Struct:
|
||||
if ptrType == reflect.TypeFor[time.Time]() {
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
return fmt.Errorf("cannot set Date to %s", ptr.Kind())
|
||||
}
|
||||
timeDate, err := napi.ToDate(napiValue).Time()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.Set(reflect.ValueOf(timeDate))
|
||||
return nil
|
||||
case napi.TypeArray:
|
||||
napiArray := napi.ToArray(napiValue)
|
||||
size, err := napiArray.Length()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch ptr.Kind() {
|
||||
case reflect.Slice:
|
||||
value := reflect.MakeSlice(ptrType, size, size)
|
||||
for index := range size {
|
||||
napiValue, err := napiArray.Get(index)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if err = valueFrom(napiValue, value.Index(index)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ptr.Set(value)
|
||||
return nil
|
||||
case reflect.Array:
|
||||
value := reflect.New(ptrType)
|
||||
for index := range min(size, value.Len()) {
|
||||
napiValue, err := napiArray.Get(index)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if err = valueFrom(napiValue, value.Index(index)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ptr.Set(value)
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot set Array to %s", ptr.Kind())
|
||||
}
|
||||
case napi.TypeBuffer:
|
||||
switch ptr.Kind() {
|
||||
case reflect.Slice:
|
||||
if ptrType == reflect.TypeFor[[]byte]() {
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
return fmt.Errorf("cannot set Buffer to %s", ptr.Kind())
|
||||
}
|
||||
buff, err := napi.ToBuffer(napiValue).Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.SetBytes(buff)
|
||||
return nil
|
||||
case napi.TypeObject:
|
||||
obj := napi.ToObject(napiValue)
|
||||
switch ptr.Kind() {
|
||||
case reflect.Struct:
|
||||
ptr.Set(reflect.New(ptrType).Elem())
|
||||
for keyIndex := range ptrType.NumField() {
|
||||
field, fieldType := ptr.Field(keyIndex), ptrType.Field(keyIndex)
|
||||
if !fieldType.IsExported() || fieldType.Tag.Get(propertiesTagName) == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
keyName, omitEmpty, omitZero := fieldType.Name, false, false
|
||||
if strings.Count(fieldType.Tag.Get(propertiesTagName), ",") > 0 {
|
||||
fields := strings.SplitN(fieldType.Tag.Get(propertiesTagName), ",", 2)
|
||||
keyName = fields[0]
|
||||
switch fields[1] {
|
||||
case "omitempty":
|
||||
omitEmpty = true
|
||||
case "omitzero":
|
||||
omitZero = true
|
||||
}
|
||||
} else {
|
||||
omitEmpty, omitZero = true, true
|
||||
}
|
||||
|
||||
if ok, err := obj.Has(keyName); err != nil {
|
||||
return err
|
||||
} else if !ok && !(omitEmpty || omitZero) {
|
||||
return fmt.Errorf("cannot set %s to %s", keyName, ptr.Kind())
|
||||
}
|
||||
|
||||
value, err := obj.Get(keyName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
valueTypeof, _ := value.Type()
|
||||
if omitEmpty || omitZero {
|
||||
switch valueTypeof {
|
||||
case napi.TypeUndefined, napi.TypeNull, napi.TypeUnkown:
|
||||
continue
|
||||
case napi.TypeString:
|
||||
if str, _ := napi.ToString(value).Utf8Value(); str == "" {
|
||||
continue
|
||||
}
|
||||
case napi.TypeDate:
|
||||
if timeDate, _ := napi.ToDate(value).Time(); timeDate.Unix() == 0 {
|
||||
continue
|
||||
}
|
||||
case napi.TypeBigInt:
|
||||
if numberValue, _ := napi.ToBigint(value).Int64(); numberValue == 0 {
|
||||
continue
|
||||
}
|
||||
case napi.TypeNumber:
|
||||
if numberValue, _ := napi.ToNumber(value).Int(); numberValue == 0 {
|
||||
continue
|
||||
}
|
||||
case napi.TypeArray:
|
||||
if size, _ := napi.ToArray(value).Length(); size == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
valueOf := reflect.New(fieldType.Type).Elem()
|
||||
if err := valueFrom(value, valueOf); err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(valueOf)
|
||||
}
|
||||
return nil
|
||||
case reflect.Map:
|
||||
// Check if key is string, bool, int*, uint*, float*, else return error
|
||||
switch ptrType.Key().Kind() {
|
||||
case reflect.String:
|
||||
case reflect.Bool:
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
case reflect.Float32, reflect.Float64:
|
||||
default:
|
||||
return fmt.Errorf("cannot set Object to %s", ptr.Kind())
|
||||
}
|
||||
|
||||
goMap := reflect.MakeMap(ptrType)
|
||||
for keyName, value := range obj.Seq() {
|
||||
keySetValue := reflect.New(ptrType.Key()).Elem()
|
||||
switch ptrType.Key().Kind() {
|
||||
case reflect.String:
|
||||
keySetValue.SetString(keyName)
|
||||
case reflect.Bool:
|
||||
boolV, err := strconv.ParseBool(keyName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keySetValue.SetBool(boolV)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
intV, err := strconv.ParseInt(keyName, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keySetValue.SetInt(intV)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
intV, err := strconv.ParseUint(keyName, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keySetValue.SetUint(intV)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
floatV, err := strconv.ParseFloat(keyName, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keySetValue.SetFloat(floatV)
|
||||
}
|
||||
|
||||
valueOf := reflect.New(ptrType.Elem()).Elem()
|
||||
if err := valueFrom(value, valueOf); err != nil {
|
||||
return err
|
||||
}
|
||||
goMap.SetMapIndex(keySetValue, valueOf)
|
||||
}
|
||||
ptr.Set(goMap)
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot set Object to %s", ptr.Kind())
|
||||
}
|
||||
default:
|
||||
println(typeOf.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
123
js/js_func.go
Normal file
123
js/js_func.go
Normal file
@ -0,0 +1,123 @@
|
||||
package js
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go"
|
||||
internalNapi "sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
// Create napi bind to golang functions
|
||||
func GoFuncOf(env napi.EnvType, function any) (napi.ValueType, error) {
|
||||
return funcOf(env, reflect.ValueOf(function))
|
||||
}
|
||||
|
||||
func funcOf(env napi.EnvType, ptr reflect.Value) (napi.ValueType, error) {
|
||||
if ptr.Kind() != reflect.Func {
|
||||
return nil, fmt.Errorf("return function to return napi value")
|
||||
}
|
||||
|
||||
funcName := runtime.FuncForPC(ptr.Pointer()).Name()
|
||||
switch v := ptr.Interface().(type) {
|
||||
case nil:
|
||||
return nil, nil
|
||||
case napi.Callback:
|
||||
return napi.CreateFunction(env, funcName, v)
|
||||
case internalNapi.Callback:
|
||||
return napi.CreateFunctionNapi(env, funcName, v)
|
||||
default:
|
||||
return napi.CreateFunction(env, funcName, func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
|
||||
fnType := ptr.Type()
|
||||
returnValues := []reflect.Value{}
|
||||
switch {
|
||||
case fnType.NumIn() == 0 && fnType.NumOut() == 0:
|
||||
returnValues = ptr.Call([]reflect.Value{})
|
||||
case !fnType.IsVariadic():
|
||||
returnValues = ptr.Call(goValuesInFunc(ptr, args, false))
|
||||
default:
|
||||
returnValues = ptr.CallSlice(goValuesInFunc(ptr, args, true))
|
||||
}
|
||||
|
||||
switch len(returnValues) {
|
||||
case 0:
|
||||
return nil, nil
|
||||
case 1:
|
||||
return valueOf(env, returnValues[0])
|
||||
default:
|
||||
lastValue := returnValues[len(returnValues)-1]
|
||||
if lastValue.CanConvert(reflect.TypeFor[error]()) {
|
||||
returnValues = returnValues[:len(returnValues)-1]
|
||||
if !lastValue.IsNil() {
|
||||
if err := lastValue.Interface().(error); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch len(returnValues) {
|
||||
case 1:
|
||||
// Return value from return
|
||||
return valueOf(env, returnValues[0])
|
||||
default:
|
||||
// Create array
|
||||
arr, err := napi.CreateArray(env, len(returnValues))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Append values to js array
|
||||
for index, value := range returnValues {
|
||||
napiValue, err := valueOf(env, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if err = arr.Set(index, napiValue); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func goValuesInFunc(ptr reflect.Value, jsArgs []napi.ValueType, variadic bool) (values []reflect.Value) {
|
||||
if variadic && (ptr.Type().NumIn()-1 > 0) && ptr.Type().NumIn()-1 < len(jsArgs) {
|
||||
panic(fmt.Errorf("require minimun %d arguments, called with %d", ptr.Type().NumIn()-1, len(jsArgs)))
|
||||
} else if !variadic &&ptr.Type().NumIn() != len(jsArgs) {
|
||||
panic(fmt.Errorf("require %d arguments, called with %d", ptr.Type().NumIn(), len(jsArgs)))
|
||||
}
|
||||
|
||||
size := ptr.Type().NumIn()
|
||||
if variadic {
|
||||
size--
|
||||
}
|
||||
|
||||
values = make([]reflect.Value, size)
|
||||
for index := range values {
|
||||
valueOf := reflect.New(ptr.Type().In(index))
|
||||
if err := valueFrom(jsArgs[index], valueOf); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
values[index] = valueOf
|
||||
}
|
||||
|
||||
if variadic {
|
||||
variadicType := ptr.Type().In(size).Elem()
|
||||
|
||||
valueAppend := jsArgs[size:]
|
||||
valueOf := reflect.MakeSlice(reflect.SliceOf(variadicType), len(valueAppend), len(valueAppend))
|
||||
for index := range valueAppend {
|
||||
if err := valueFrom(valueAppend[index], valueOf.Index(index)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
values = append(values, valueOf)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
118
js/promise.go
118
js/promise.go
@ -1,118 +0,0 @@
|
||||
package js
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
)
|
||||
|
||||
type Promise struct {
|
||||
Promise napi.Promise
|
||||
ThreadsafeFunction napi.ThreadsafeFunction
|
||||
Result any
|
||||
ResultType PromiseResultType
|
||||
}
|
||||
|
||||
type PromiseResultType string
|
||||
|
||||
type PromiseProvider interface {
|
||||
Resolve(resolution any)
|
||||
Reject(rejection any)
|
||||
}
|
||||
|
||||
var _ PromiseProvider = &Promise{}
|
||||
|
||||
const (
|
||||
PromiseResultTypeResolved PromiseResultType = "resolved"
|
||||
PromiseResultTypeRejected PromiseResultType = "rejected"
|
||||
)
|
||||
|
||||
var ErrPromiseSettled = errors.New(
|
||||
"Promise: Cannot resolve/reject a settled promise",
|
||||
)
|
||||
|
||||
func (p *Promise) Resolve(resolution any) {
|
||||
p.ensurePending()
|
||||
|
||||
p.Result = resolution
|
||||
p.ResultType = PromiseResultTypeResolved
|
||||
|
||||
// function has already been acquired during reset
|
||||
defer p.release()
|
||||
p.settle()
|
||||
}
|
||||
|
||||
func (p *Promise) Reject(rejection any) {
|
||||
p.ensurePending()
|
||||
|
||||
p.Result = rejection
|
||||
p.ResultType = PromiseResultTypeRejected
|
||||
|
||||
// function has already been acquired during reset
|
||||
defer p.release()
|
||||
p.settle()
|
||||
}
|
||||
|
||||
func (p *Promise) reset(e Env) {
|
||||
np, st := napi.CreatePromise(e.Env)
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
|
||||
asyncResourceName := e.ValueOf("napi-go/js-promise")
|
||||
fn := e.FuncOf(func(env Env, this Value, args []Value) any {
|
||||
value := env.ValueOf(p.Result)
|
||||
|
||||
st := napi.StatusOK
|
||||
switch p.ResultType {
|
||||
case PromiseResultTypeResolved:
|
||||
st = napi.ResolveDeferred(env.Env, p.Promise.Deferred, value.Value)
|
||||
case PromiseResultTypeRejected:
|
||||
st = napi.RejectDeferred(env.Env, p.Promise.Deferred, value.Value)
|
||||
}
|
||||
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
tsFn, st := napi.CreateThreadsafeFunction(
|
||||
e.Env,
|
||||
fn.Value.Value,
|
||||
nil, asyncResourceName.Value,
|
||||
0,
|
||||
1, // initialize with 1 acquisition
|
||||
)
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
|
||||
*p = Promise{
|
||||
Promise: np,
|
||||
ThreadsafeFunction: tsFn,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Promise) ensurePending() {
|
||||
if p.ResultType != "" {
|
||||
panic(ErrPromiseSettled)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Promise) settle() {
|
||||
st := napi.CallThreadsafeFunction(p.ThreadsafeFunction)
|
||||
if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Promise) release() {
|
||||
st := napi.ReleaseThreadsafeFunction(p.ThreadsafeFunction)
|
||||
if st == napi.StatusClosing {
|
||||
p.ThreadsafeFunction = nil
|
||||
} else if st != napi.StatusOK {
|
||||
panic(napi.StatusError(st))
|
||||
}
|
||||
}
|
14
js/value.go
14
js/value.go
@ -1,14 +0,0 @@
|
||||
package js
|
||||
|
||||
import (
|
||||
"github.com/akshayganeshen/napi-go"
|
||||
)
|
||||
|
||||
type Value struct {
|
||||
Env Env
|
||||
Value napi.Value
|
||||
}
|
||||
|
||||
func (v Value) GetEnv() Env {
|
||||
return v.Env
|
||||
}
|
341
js_native_api.go
341
js_native_api.go
@ -1,341 +0,0 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func GetUndefined(env Env) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_get_undefined(
|
||||
C.napi_env(env),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func GetNull(env Env) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_get_null(
|
||||
C.napi_env(env),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func GetGlobal(env Env) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_get_global(
|
||||
C.napi_env(env),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func GetBoolean(env Env, value bool) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_get_boolean(
|
||||
C.napi_env(env),
|
||||
C.bool(value),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreateObject(env Env) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_create_object(
|
||||
C.napi_env(env),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreateArray(env Env) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_create_array(
|
||||
C.napi_env(env),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreateArrayWithLength(env Env, length int) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_create_array_with_length(
|
||||
C.napi_env(env),
|
||||
C.size_t(length),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreateDouble(env Env, value float64) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_create_double(
|
||||
C.napi_env(env),
|
||||
C.double(value),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreateStringUtf8(env Env, str string) (Value, Status) {
|
||||
cstr := C.CString(str)
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
|
||||
var result Value
|
||||
status := Status(C.napi_create_string_utf8(
|
||||
C.napi_env(env),
|
||||
cstr,
|
||||
C.size_t(len([]byte(str))), // must pass number of bytes
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreateSymbol(env Env, description Value) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_create_symbol(
|
||||
C.napi_env(env),
|
||||
C.napi_value(description),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func CreateFunction(env Env, name string, cb Callback) (Value, Status) {
|
||||
provider, status := getInstanceData(env)
|
||||
if status != StatusOK || provider == nil {
|
||||
return nil, status
|
||||
}
|
||||
|
||||
return provider.GetCallbackData().CreateCallback(env, name, cb)
|
||||
}
|
||||
|
||||
func CreateError(env Env, code, msg Value) (Value, Status) {
|
||||
var result Value
|
||||
status := Status(C.napi_create_error(
|
||||
C.napi_env(env),
|
||||
C.napi_value(code),
|
||||
C.napi_value(msg),
|
||||
(*C.napi_value)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func Typeof(env Env, value Value) (ValueType, Status) {
|
||||
var result ValueType
|
||||
status := Status(C.napi_typeof(
|
||||
C.napi_env(env),
|
||||
C.napi_value(value),
|
||||
(*C.napi_valuetype)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func GetValueDouble(env Env, value Value) (float64, Status) {
|
||||
var result float64
|
||||
status := Status(C.napi_get_value_double(
|
||||
C.napi_env(env),
|
||||
C.napi_value(value),
|
||||
(*C.double)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func GetValueBool(env Env, value Value) (bool, Status) {
|
||||
var result bool
|
||||
status := Status(C.napi_get_value_bool(
|
||||
C.napi_env(env),
|
||||
C.napi_value(value),
|
||||
(*C.bool)(unsafe.Pointer(&result)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func GetValueStringUtf8(env Env, value Value) (string, Status) {
|
||||
// call napi_get_value_string_utf8 twice
|
||||
// first is to get number of bytes
|
||||
// second is to populate the actual string buffer
|
||||
bufsize := C.size_t(0)
|
||||
var strsize C.size_t
|
||||
|
||||
status := Status(C.napi_get_value_string_utf8(
|
||||
C.napi_env(env),
|
||||
C.napi_value(value),
|
||||
nil,
|
||||
bufsize,
|
||||
&strsize,
|
||||
))
|
||||
|
||||
if status != StatusOK {
|
||||
return "", status
|
||||
}
|
||||
|
||||
// ensure there is room for the null terminator as well
|
||||
strsize++
|
||||
cstr := (*C.char)(C.malloc(C.sizeof_char * strsize))
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
|
||||
status = Status(C.napi_get_value_string_utf8(
|
||||
C.napi_env(env),
|
||||
C.napi_value(value),
|
||||
cstr,
|
||||
strsize,
|
||||
&strsize,
|
||||
))
|
||||
|
||||
if status != StatusOK {
|
||||
return "", status
|
||||
}
|
||||
|
||||
return C.GoStringN(
|
||||
(*C.char)(cstr),
|
||||
(C.int)(strsize),
|
||||
), status
|
||||
}
|
||||
|
||||
func SetProperty(env Env, object, key, value Value) Status {
|
||||
return Status(C.napi_set_property(
|
||||
C.napi_env(env),
|
||||
C.napi_value(object),
|
||||
C.napi_value(key),
|
||||
C.napi_value(value),
|
||||
))
|
||||
}
|
||||
|
||||
func SetElement(env Env, object Value, index int, value Value) Status {
|
||||
return Status(C.napi_set_element(
|
||||
C.napi_env(env),
|
||||
C.napi_value(object),
|
||||
C.uint32_t(index),
|
||||
C.napi_value(value),
|
||||
))
|
||||
}
|
||||
|
||||
func StrictEquals(env Env, lhs, rhs Value) (bool, Status) {
|
||||
var result bool
|
||||
status := Status(C.napi_strict_equals(
|
||||
C.napi_env(env),
|
||||
C.napi_value(lhs),
|
||||
C.napi_value(rhs),
|
||||
(*C.bool)(&result),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
type GetCbInfoResult struct {
|
||||
Args []Value
|
||||
This Value
|
||||
}
|
||||
|
||||
func GetCbInfo(env Env, info CallbackInfo) (GetCbInfoResult, Status) {
|
||||
// call napi_get_cb_info twice
|
||||
// first is to get total number of arguments
|
||||
// second is to populate the actual arguments
|
||||
argc := C.size_t(0)
|
||||
status := Status(C.napi_get_cb_info(
|
||||
C.napi_env(env),
|
||||
C.napi_callback_info(info),
|
||||
&argc,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
))
|
||||
|
||||
if status != StatusOK {
|
||||
return GetCbInfoResult{}, status
|
||||
}
|
||||
|
||||
argv := make([]Value, int(argc))
|
||||
var cArgv unsafe.Pointer
|
||||
if argc > 0 {
|
||||
cArgv = unsafe.Pointer(&argv[0]) // must pass element pointer
|
||||
}
|
||||
|
||||
var thisArg Value
|
||||
|
||||
status = Status(C.napi_get_cb_info(
|
||||
C.napi_env(env),
|
||||
C.napi_callback_info(info),
|
||||
&argc,
|
||||
(*C.napi_value)(cArgv),
|
||||
(*C.napi_value)(unsafe.Pointer(&thisArg)),
|
||||
nil,
|
||||
))
|
||||
|
||||
return GetCbInfoResult{
|
||||
Args: argv,
|
||||
This: thisArg,
|
||||
}, status
|
||||
}
|
||||
|
||||
func Throw(env Env, err Value) Status {
|
||||
return Status(C.napi_throw(
|
||||
C.napi_env(env),
|
||||
C.napi_value(err),
|
||||
))
|
||||
}
|
||||
|
||||
func ThrowError(env Env, code, msg string) Status {
|
||||
codeCStr, msgCCstr := C.CString(code), C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(codeCStr))
|
||||
defer C.free(unsafe.Pointer(msgCCstr))
|
||||
|
||||
return Status(C.napi_throw_error(
|
||||
C.napi_env(env),
|
||||
codeCStr,
|
||||
msgCCstr,
|
||||
))
|
||||
}
|
||||
|
||||
func CreatePromise(env Env) (Promise, Status) {
|
||||
var result Promise
|
||||
status := Status(C.napi_create_promise(
|
||||
C.napi_env(env),
|
||||
(*C.napi_deferred)(unsafe.Pointer(&result.Deferred)),
|
||||
(*C.napi_value)(unsafe.Pointer(&result.Value)),
|
||||
))
|
||||
return result, status
|
||||
}
|
||||
|
||||
func ResolveDeferred(env Env, deferred Deferred, resolution Value) Status {
|
||||
return Status(C.napi_resolve_deferred(
|
||||
C.napi_env(env),
|
||||
C.napi_deferred(deferred),
|
||||
C.napi_value(resolution),
|
||||
))
|
||||
}
|
||||
|
||||
func RejectDeferred(env Env, deferred Deferred, rejection Value) Status {
|
||||
return Status(C.napi_reject_deferred(
|
||||
C.napi_env(env),
|
||||
C.napi_deferred(deferred),
|
||||
C.napi_value(rejection),
|
||||
))
|
||||
}
|
||||
|
||||
func SetInstanceData(env Env, data any) Status {
|
||||
provider, status := getInstanceData(env)
|
||||
if status != StatusOK || provider == nil {
|
||||
return status
|
||||
}
|
||||
|
||||
provider.SetUserData(data)
|
||||
return status
|
||||
}
|
||||
|
||||
func GetInstanceData(env Env) (any, Status) {
|
||||
provider, status := getInstanceData(env)
|
||||
if status != StatusOK || provider == nil {
|
||||
return nil, status
|
||||
}
|
||||
|
||||
return provider.GetUserData(), status
|
||||
}
|
40
makefile
40
makefile
@ -1,40 +0,0 @@
|
||||
all: doc
|
||||
clean: clean-doc
|
||||
|
||||
EXAMPLE_DIR = docs/examples
|
||||
EXAMPLE_PACKAGES = \
|
||||
async-promise \
|
||||
callback \
|
||||
describe-args \
|
||||
hello-world \
|
||||
js
|
||||
|
||||
NAPI_LIB_SUFFIX = .node
|
||||
|
||||
TARGET_BUILDDIR = build
|
||||
|
||||
EXAMPLE_BINDINGS = $(addsuffix $(NAPI_LIB_SUFFIX),$(EXAMPLE_PACKAGES))
|
||||
TARGET_EXAMPLES = \
|
||||
$(addprefix $(TARGET_BUILDDIR)/, $(EXAMPLE_BINDINGS))
|
||||
|
||||
# TODO: Configure CGO_LDFLAGS_ALLOW for non-darwin systems.
|
||||
CGO_LDFLAGS_ALLOW = (-Wl,(-undefined,dynamic_lookup|-no_pie|-search_paths_first))
|
||||
|
||||
doc: $(TARGET_EXAMPLES)
|
||||
|
||||
$(TARGET_EXAMPLES): | $(TARGET_BUILDDIR)
|
||||
$(TARGET_EXAMPLES): $(TARGET_BUILDDIR)/%$(NAPI_LIB_SUFFIX): $(EXAMPLE_DIR)/%
|
||||
CGO_LDFLAGS_ALLOW='$(CGO_LDFLAGS_ALLOW)' \
|
||||
go build -buildmode=c-shared -o "$(@)" "./$(<)/"
|
||||
|
||||
$(TARGET_BUILDDIR):
|
||||
mkdir -p "$(TARGET_BUILDDIR)"
|
||||
|
||||
clean:
|
||||
rmdir "$(TARGET_BUILDDIR)"
|
||||
|
||||
clean-doc:
|
||||
rm -f $(patsubst %,"%",$(TARGET_EXAMPLES))
|
||||
|
||||
.PHONY: all doc
|
||||
.PHONY: clean clean-doc
|
50
napi_env.go
Normal file
50
napi_env.go
Normal file
@ -0,0 +1,50 @@
|
||||
package napi
|
||||
|
||||
import "sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
|
||||
type EnvType interface {
|
||||
NapiValue() napi.Env // Primitive value to NAPI call
|
||||
Global() (*Object, error)
|
||||
Undefined() (ValueType, error)
|
||||
Null() (ValueType, error)
|
||||
}
|
||||
|
||||
// Return N-API env reference
|
||||
func N_APIEnv(env napi.Env) EnvType { return &Env{env} }
|
||||
|
||||
// N-API Env
|
||||
type Env struct{
|
||||
NapiEnv napi.Env
|
||||
}
|
||||
|
||||
// Return [napi.Env] to point from internal napi cgo
|
||||
func (e *Env) NapiValue() napi.Env {
|
||||
return e.NapiEnv
|
||||
}
|
||||
|
||||
// Return representantion to 'This' [*Object]
|
||||
func (e *Env) Global() (*Object, error) {
|
||||
napiValue, err := mustValueErr(napi.GetGlobal(e.NapiEnv))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToObject(N_APIValue(e, napiValue)), nil
|
||||
}
|
||||
|
||||
// Return Undefined value
|
||||
func (e *Env) Undefined() (ValueType, error) {
|
||||
napiValue, err := mustValueErr(napi.GetUndefined(e.NapiEnv))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return N_APIValue(e, napiValue), nil
|
||||
}
|
||||
|
||||
// Return Null value
|
||||
func (e *Env) Null() (ValueType, error) {
|
||||
napiValue, err := mustValueErr(napi.GetNull(e.NapiEnv))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return N_APIValue(e, napiValue), nil
|
||||
}
|
35
napi_status.go
Normal file
35
napi_status.go
Normal file
@ -0,0 +1,35 @@
|
||||
package napi
|
||||
|
||||
import "sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
|
||||
// Process status to return error if StatusOK return nil on error
|
||||
func mustValueErr[T any](input T, status napi.Status) (T, error) {
|
||||
if status != napi.StatusOK {
|
||||
return input, napi.StatusError(status)
|
||||
}
|
||||
return input, nil
|
||||
}
|
||||
|
||||
// return error from status
|
||||
func singleMustValueErr(status napi.Status) error {
|
||||
if status != napi.StatusOK {
|
||||
return napi.StatusError(status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process status to return error if StatusOK return nil on error
|
||||
func mustValueErr2[T any](input T, _ bool, status napi.Status) (T, error) {
|
||||
if status != napi.StatusOK {
|
||||
return input, napi.StatusError(status)
|
||||
}
|
||||
return input, nil
|
||||
}
|
||||
|
||||
// Process status to return error if StatusOK return nil on error
|
||||
func mustValueErr3[T, C any](input T, i2 C, status napi.Status) (T, C, error) {
|
||||
if status != napi.StatusOK {
|
||||
return input, i2, napi.StatusError(status)
|
||||
}
|
||||
return input, i2, nil
|
||||
}
|
167
napi_value.go
Normal file
167
napi_value.go
Normal file
@ -0,0 +1,167 @@
|
||||
package napi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type ValueType interface {
|
||||
NapiValue() napi.Value // Primitive value to NAPI call
|
||||
NapiEnv() napi.Env // NAPI Env to NAPI call
|
||||
|
||||
Env() EnvType // NAPI Env to NAPI call
|
||||
Type() (NapiType, error) // NAPI Type of value
|
||||
}
|
||||
|
||||
type (
|
||||
value = ValueType // to dont expose to external structs
|
||||
|
||||
// Generic type to NAPI value
|
||||
Value struct {
|
||||
env EnvType
|
||||
valueOf napi.Value
|
||||
}
|
||||
|
||||
NapiType int // Return typeof of Value
|
||||
)
|
||||
|
||||
const (
|
||||
TypeUnkown NapiType = iota
|
||||
TypeUndefined
|
||||
TypeNull
|
||||
TypeBoolean
|
||||
TypeNumber
|
||||
TypeBigInt
|
||||
TypeString
|
||||
TypeSymbol
|
||||
TypeObject
|
||||
TypeFunction
|
||||
TypeExternal
|
||||
TypeTypedArray
|
||||
TypePromise
|
||||
TypeDataView
|
||||
TypeBuffer
|
||||
TypeDate
|
||||
TypeArray
|
||||
TypeArrayBuffer
|
||||
TypeError
|
||||
)
|
||||
|
||||
var napiTypeNames = map[NapiType]string{
|
||||
TypeUnkown: "Unknown",
|
||||
TypeUndefined: "Undefined",
|
||||
TypeNull: "Null",
|
||||
TypeBoolean: "Boolean",
|
||||
TypeNumber: "Number",
|
||||
TypeBigInt: "BigInt",
|
||||
TypeString: "String",
|
||||
TypeSymbol: "Symbol",
|
||||
TypeObject: "Object",
|
||||
TypeFunction: "Function",
|
||||
TypeExternal: "External",
|
||||
TypeTypedArray: "TypedArray",
|
||||
TypePromise: "Promise",
|
||||
TypeDataView: "DaraView",
|
||||
TypeBuffer: "Buffer",
|
||||
TypeDate: "Date",
|
||||
TypeArray: "Array",
|
||||
TypeArrayBuffer: "ArrayBuffer",
|
||||
TypeError: "Error",
|
||||
}
|
||||
|
||||
// Return [ValueType] from [napi.Value]
|
||||
func N_APIValue(env EnvType, value napi.Value) ValueType {
|
||||
return &Value{env: env, valueOf: value}
|
||||
}
|
||||
|
||||
func (v *Value) NapiValue() napi.Value { return v.valueOf }
|
||||
func (v *Value) NapiEnv() napi.Env { return v.env.NapiValue() }
|
||||
func (v *Value) Env() EnvType { return v.env }
|
||||
|
||||
func (v *Value) Type() (NapiType, error) {
|
||||
isTypedArray, err := mustValueErr(napi.IsTypedArray(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
isPromise, err := mustValueErr(napi.IsPromise(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
isDataView, err := mustValueErr(napi.IsDataView(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
isBuffer, err := mustValueErr(napi.IsBuffer(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
isDate, err := mustValueErr(napi.IsDate(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
isArray, err := mustValueErr(napi.IsArray(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
isArrayBuffer, err := mustValueErr(napi.IsArrayBuffer(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
isError, err := mustValueErr(napi.IsError(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
isTypeof, err := mustValueErr(napi.Typeof(v.NapiEnv(), v.NapiValue()))
|
||||
if err != nil {
|
||||
return TypeUnkown, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case isTypedArray:
|
||||
return TypeTypedArray, nil
|
||||
case isPromise:
|
||||
return TypePromise, nil
|
||||
case isDataView:
|
||||
return TypeDataView, nil
|
||||
case isBuffer:
|
||||
return TypeBuffer, nil
|
||||
case isDate:
|
||||
return TypeDate, nil
|
||||
case isArray:
|
||||
return TypeArray, nil
|
||||
case isArrayBuffer:
|
||||
return TypeArrayBuffer, nil
|
||||
case isError:
|
||||
return TypeError, nil
|
||||
case isTypeof == napi.ValueTypeUndefined:
|
||||
return TypeUndefined, nil
|
||||
case isTypeof == napi.ValueTypeNull:
|
||||
return TypeNull, nil
|
||||
case isTypeof == napi.ValueTypeBoolean:
|
||||
return TypeBoolean, nil
|
||||
case isTypeof == napi.ValueTypeNumber:
|
||||
return TypeNumber, nil
|
||||
case isTypeof == napi.ValueTypeString:
|
||||
return TypeString, nil
|
||||
case isTypeof == napi.ValueTypeSymbol:
|
||||
return TypeSymbol, nil
|
||||
case isTypeof == napi.ValueTypeObject:
|
||||
return TypeObject, nil
|
||||
case isTypeof == napi.ValueTypeFunction:
|
||||
return TypeFunction, nil
|
||||
case isTypeof == napi.ValueTypeExternal:
|
||||
return TypeExternal, nil
|
||||
case isTypeof == napi.ValueTypeBigint:
|
||||
return TypeBigInt, nil
|
||||
}
|
||||
|
||||
return TypeUnkown, nil
|
||||
}
|
||||
|
||||
func (t NapiType) String() string {
|
||||
if name, ok := napiTypeNames[t]; ok {
|
||||
return name
|
||||
}
|
||||
return fmt.Sprintf("Unknown NapiType %d", t)
|
||||
}
|
114
number.go
Normal file
114
number.go
Normal file
@ -0,0 +1,114 @@
|
||||
package napi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type Number struct{ value }
|
||||
type Bigint struct{ value }
|
||||
|
||||
// Convert [ValueType] to [*Number]
|
||||
func ToNumber(o ValueType) *Number { return &Number{o} }
|
||||
|
||||
// Convert [ValueType] to [*Bigint]
|
||||
func ToBigint(o ValueType) *Bigint { return &Bigint{o} }
|
||||
|
||||
func (num *Number) Float() (float64, error) {
|
||||
return mustValueErr(napi.GetValueDouble(num.NapiEnv(), num.NapiValue()))
|
||||
}
|
||||
|
||||
func (num *Number) Int() (int64, error) {
|
||||
return mustValueErr(napi.GetValueInt64(num.NapiEnv(), num.NapiValue()))
|
||||
}
|
||||
|
||||
func (num *Number) Uint32() (uint32, error) {
|
||||
return mustValueErr(napi.GetValueUint32(num.NapiEnv(), num.NapiValue()))
|
||||
}
|
||||
|
||||
func (num *Number) Int32() (int32, error) {
|
||||
return mustValueErr(napi.GetValueInt32(num.NapiEnv(), num.NapiValue()))
|
||||
}
|
||||
|
||||
func (big *Bigint) Int64() (int64, error) {
|
||||
return mustValueErr2(napi.GetValueBigIntInt64(big.NapiEnv(), big.NapiValue()))
|
||||
}
|
||||
func (big *Bigint) Uint64() (uint64, error) {
|
||||
return mustValueErr2(napi.GetValueBigIntUint64(big.NapiEnv(), big.NapiValue()))
|
||||
}
|
||||
|
||||
func CreateBigint[T int64 | uint64](env EnvType, valueOf T) (*Bigint, error) {
|
||||
var value napi.Value
|
||||
var err error
|
||||
switch v := any(valueOf).(type) {
|
||||
case int64:
|
||||
if value, err = mustValueErr(napi.CreateBigIntInt64(env.NapiValue(), v)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case uint64:
|
||||
if value, err = mustValueErr(napi.CreateBigIntUint64(env.NapiValue(), v)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &Bigint{value: &Value{env: env, valueOf: value}}, nil
|
||||
}
|
||||
|
||||
func CreateNumber[T ~int | ~uint | ~int8 | ~uint8 | ~int16 | ~uint16 | ~int32 | ~uint32 | ~int64 | ~uint64 | ~float32 | ~float64](env EnvType, n T) (*Number, error) {
|
||||
var value napi.Value
|
||||
var err error
|
||||
switch v := any(n).(type) {
|
||||
case int:
|
||||
if value, err = mustValueErr(napi.CreateInt64(env.NapiValue(), int64(v))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case uint:
|
||||
if value, err = mustValueErr(napi.CreateInt64(env.NapiValue(), int64(v))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case int8:
|
||||
if value, err = mustValueErr(napi.CreateInt64(env.NapiValue(), int64(v))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case uint8:
|
||||
if value, err = mustValueErr(napi.CreateInt64(env.NapiValue(), int64(v))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case int16:
|
||||
if value, err = mustValueErr(napi.CreateInt64(env.NapiValue(), int64(v))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case uint16:
|
||||
if value, err = mustValueErr(napi.CreateInt64(env.NapiValue(), int64(v))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case int32:
|
||||
if value, err = mustValueErr(napi.CreateInt32(env.NapiValue(), v)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case uint32:
|
||||
if value, err = mustValueErr(napi.CreateUint32(env.NapiValue(), v)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case int64:
|
||||
if value, err = mustValueErr(napi.CreateInt64(env.NapiValue(), v)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case uint64:
|
||||
if value, err = mustValueErr(napi.CreateInt64(env.NapiValue(), int64(v))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case float32:
|
||||
if value, err = mustValueErr(napi.CreateDouble(env.NapiValue(), float64(v))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case float64:
|
||||
if value, err = mustValueErr(napi.CreateDouble(env.NapiValue(), v)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid number type")
|
||||
}
|
||||
return ToNumber(N_APIValue(env, value)), err
|
||||
}
|
134
object.go
Normal file
134
object.go
Normal file
@ -0,0 +1,134 @@
|
||||
package napi
|
||||
|
||||
import (
|
||||
"iter"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type Object struct{ value }
|
||||
|
||||
// Convert ValueType to [*Object]
|
||||
func ToObject(o ValueType) *Object { return &Object{o} }
|
||||
|
||||
// Create [*Object]
|
||||
func CreateObject(env EnvType) (*Object, error) {
|
||||
napiValue, err := mustValueErr(napi.CreateObject(env.NapiValue()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToObject(N_APIValue(env, napiValue)), nil
|
||||
}
|
||||
|
||||
// Check if exists named property.
|
||||
func (obj *Object) Has(name string) (bool, error) {
|
||||
return mustValueErr(napi.HasNamedProperty(obj.NapiEnv(), obj.NapiValue(), name))
|
||||
}
|
||||
|
||||
// Checks whether a own property is present.
|
||||
func (obj *Object) HasOwnProperty(key ValueType) (bool, error) {
|
||||
return mustValueErr(napi.HasOwnProperty(obj.NapiEnv(), obj.NapiValue(), key.NapiValue()))
|
||||
}
|
||||
|
||||
// Checks whether a own property is present.
|
||||
func (obj *Object) HasOwnPropertyString(keyString string) (bool, error) {
|
||||
napiString, err := CreateString(obj.Env(), keyString)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return obj.HasOwnProperty(napiString)
|
||||
}
|
||||
|
||||
// Gets a property.
|
||||
func (obj *Object) Get(key string) (ValueType, error) {
|
||||
keyValue, err := CreateString(obj.Env(), key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.GetWithValue(keyValue)
|
||||
}
|
||||
|
||||
// Gets a property.
|
||||
func (obj *Object) GetWithValue(key ValueType) (ValueType, error) {
|
||||
napiValue, err := mustValueErr(napi.GetProperty(obj.Env().NapiValue(), obj.NapiValue(), key.NapiValue()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return N_APIValue(obj.Env(), napiValue), nil
|
||||
}
|
||||
|
||||
// Sets a property.
|
||||
func (obj *Object) Set(key string, value ValueType) error {
|
||||
keyValue, err := CreateString(obj.Env(), key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return obj.SetWithValue(keyValue, value)
|
||||
}
|
||||
|
||||
// Sets a property.
|
||||
func (obj *Object) SetWithValue(key, value ValueType) error {
|
||||
return singleMustValueErr(napi.SetProperty(obj.NapiEnv(), obj.NapiValue(), key.NapiValue(), value.NapiValue()))
|
||||
}
|
||||
|
||||
// Delete property.
|
||||
func (obj *Object) Delete(key string) (bool, error) {
|
||||
keyValue, err := CreateString(obj.Env(), key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return obj.DeleteWithValue(keyValue)
|
||||
}
|
||||
|
||||
// Delete property.
|
||||
func (obj *Object) DeleteWithValue(key ValueType) (bool, error) {
|
||||
return mustValueErr(napi.DeleteProperty(obj.NapiEnv(), obj.NapiValue(), key.NapiValue()))
|
||||
}
|
||||
|
||||
// Get all property names.
|
||||
func (obj *Object) GetPropertyNames() (*Array, error) {
|
||||
arrValue, err := mustValueErr(napi.GetPropertyNames(obj.NapiEnv(), obj.NapiValue()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToArray(N_APIValue(obj.Env(), arrValue)), nil
|
||||
}
|
||||
|
||||
// Checks if an object is an instance created by a constructor function,
|
||||
// this is equivalent to the JavaScript `instanceof` operator.
|
||||
func (obj *Object) InstanceOf(value ValueType) (bool, error) {
|
||||
return mustValueErr(napi.InstanceOf(obj.NapiEnv(), obj.NapiValue(), value.NapiValue()))
|
||||
}
|
||||
|
||||
// Freeze object.
|
||||
func (obj *Object) Freeze() error {
|
||||
return singleMustValueErr(napi.ObjectFreeze(obj.NapiEnv(), obj.NapiValue()))
|
||||
}
|
||||
|
||||
func (obj *Object) Seal() error {
|
||||
return singleMustValueErr(napi.ObjectSeal(obj.NapiEnv(), obj.NapiValue()))
|
||||
}
|
||||
|
||||
func (obj *Object) Seq() iter.Seq2[string, ValueType] {
|
||||
keys, err := obj.GetPropertyNames()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return func(yield func(string, ValueType) bool) {
|
||||
for key := range keys.Seq() {
|
||||
value, err := obj.GetWithValue(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
keyName, err := ToString(key).Utf8Value()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !yield(keyName, value) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
string.go
Normal file
44
string.go
Normal file
@ -0,0 +1,44 @@
|
||||
package napi
|
||||
|
||||
import (
|
||||
"unicode/utf16"
|
||||
|
||||
"sirherobrine23.com.br/Sirherobrine23/napi-go/internal/napi"
|
||||
)
|
||||
|
||||
type String struct{ value }
|
||||
|
||||
// Convert [ValueType] to [*String]
|
||||
func ToString(o ValueType) *String { return &String{o} }
|
||||
|
||||
// Create [*String] from go string
|
||||
func CreateString(env EnvType, str string) (*String, error) {
|
||||
napiString, err := mustValueErr(napi.CreateStringUtf8(env.NapiValue(), str))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToString(N_APIValue(env, napiString)), nil
|
||||
}
|
||||
|
||||
// Create string to utf16
|
||||
func CreateStringUtf16(env EnvType, str []rune) (*String, error) {
|
||||
napiString, err := mustValueErr(napi.CreateStringUtf16(env.NapiValue(), utf16.Encode(str)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToString(N_APIValue(env, napiString)), nil
|
||||
}
|
||||
|
||||
// Get String value.
|
||||
func (str *String) Utf8Value() (string, error) {
|
||||
return mustValueErr(napi.GetValueStringUtf8(str.NapiEnv(), str.NapiValue()))
|
||||
}
|
||||
|
||||
// Converts a String value to a UTF-16 encoded in rune.
|
||||
func (str *String) Utf16Value() ([]rune, error) {
|
||||
valueOf, err := mustValueErr(napi.GetValueStringUtf16(str.NapiEnv(), str.NapiValue()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return utf16.Decode(valueOf), nil
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package napi
|
||||
|
||||
/*
|
||||
#include <node/node_api.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type ValueType int
|
||||
|
||||
const (
|
||||
ValueTypeUndefined ValueType = C.napi_undefined
|
||||
ValueTypeNull ValueType = C.napi_null
|
||||
ValueTypeBoolean ValueType = C.napi_boolean
|
||||
ValueTypeNumber ValueType = C.napi_number
|
||||
ValueTypeString ValueType = C.napi_string
|
||||
ValueTypeSymbol ValueType = C.napi_symbol
|
||||
ValueTypeObject ValueType = C.napi_object
|
||||
ValueTypeFunction ValueType = C.napi_function
|
||||
ValueTypeExternal ValueType = C.napi_external
|
||||
ValueTypeBigint ValueType = C.napi_bigint
|
||||
)
|
Reference in New Issue
Block a user