chore(example): add define_class example (#2765)

This commit is contained in:
LongYinan 2025-07-06 21:43:35 -07:00 committed by GitHub
parent 0443dc5133
commit 485befffcb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 76 additions and 2 deletions

View File

@ -577,6 +577,13 @@ Generated by [AVA](https://avajs.dev).
optionalStringField?: string␊
}␊
export declare function defineClass(): typeof DynamicRustClass␊
class DynamicRustClass {␊
constructor(value: number)␊
rustMethod(): number␊
}␊
export declare function derefUint8Array(a: Uint8Array, b: Uint8ClampedArray): number␊
export declare function either3(input: string | number | boolean): number␊

View File

@ -262,6 +262,7 @@ import {
promiseRawReturnClassInstance,
ClassReturnInPromise,
acceptUntypedTypedArray,
defineClass,
} from '../index.cjs'
// import other stuff in `#[napi(module_exports)]`
import nativeAddon from '../index.cjs'
@ -581,6 +582,12 @@ test('struct with js_name and methods only (no constructor)', (t) => {
)
})
test('define class', (t) => {
const DynamicRustClass = defineClass()
const instance = new DynamicRustClass(42)
t.is(instance.rustMethod(), 42)
})
test('async self in class', async (t) => {
const b = new Bird('foo')
t.is(await b.getNameAsync(), 'foo')

View File

@ -206,6 +206,7 @@ export const customStatusCode = __napiModule.exports.customStatusCode
export const CustomStringEnum = __napiModule.exports.CustomStringEnum
export const dateToNumber = __napiModule.exports.dateToNumber
export const DEFAULT_COST = __napiModule.exports.DEFAULT_COST
export const defineClass = __napiModule.exports.defineClass
export const derefUint8Array = __napiModule.exports.derefUint8Array
export const either3 = __napiModule.exports.either3
export const either4 = __napiModule.exports.either4

View File

@ -65,6 +65,29 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule
worker.onmessage = ({ data }) => {
__wasmCreateOnMessageForFsProxy(__nodeFs)(data)
}
// The main thread of Node.js waits for all the active handles before exiting.
// But Rust threads are never waited without `thread::join`.
// So here we hack the code of Node.js to prevent the workers from being referenced (active).
// According to https://github.com/nodejs/node/blob/19e0d472728c79d418b74bddff588bea70a403d0/lib/internal/worker.js#L415,
// a worker is consist of two handles: kPublicPort and kHandle.
{
const kPublicPort = Object.getOwnPropertySymbols(worker).find(s =>
s.toString().includes("kPublicPort")
);
if (kPublicPort) {
worker[kPublicPort].ref = () => {};
}
const kHandle = Object.getOwnPropertySymbols(worker).find(s =>
s.toString().includes("kHandle")
);
if (kPublicPort) {
worker[kHandle].ref = () => {};
}
worker.unref();
}
return worker
},
overwriteImports(importObject) {
@ -230,6 +253,7 @@ module.exports.customStatusCode = __napiModule.exports.customStatusCode
module.exports.CustomStringEnum = __napiModule.exports.CustomStringEnum
module.exports.dateToNumber = __napiModule.exports.dateToNumber
module.exports.DEFAULT_COST = __napiModule.exports.DEFAULT_COST
module.exports.defineClass = __napiModule.exports.defineClass
module.exports.derefUint8Array = __napiModule.exports.derefUint8Array
module.exports.either3 = __napiModule.exports.either3
module.exports.either4 = __napiModule.exports.either4

View File

@ -521,6 +521,7 @@ module.exports.customStatusCode = nativeBinding.customStatusCode
module.exports.CustomStringEnum = nativeBinding.CustomStringEnum
module.exports.dateToNumber = nativeBinding.dateToNumber
module.exports.DEFAULT_COST = nativeBinding.DEFAULT_COST
module.exports.defineClass = nativeBinding.defineClass
module.exports.derefUint8Array = nativeBinding.derefUint8Array
module.exports.either3 = nativeBinding.either3
module.exports.either4 = nativeBinding.either4

View File

@ -539,6 +539,13 @@ export interface DefaultUseNullableStruct {
optionalStringField?: string
}
export declare function defineClass(): typeof DynamicRustClass
class DynamicRustClass {
constructor(value: number)
rustMethod(): number
}
export declare function derefUint8Array(a: Uint8Array, b: Uint8ClampedArray): number
export declare function either3(input: string | number | boolean): number

View File

@ -1,7 +1,7 @@
use napi::{
bindgen_prelude::{
Buffer, ClassInstance, JavaScriptClassExt, JsObjectValue, JsValue, ObjectFinalize, This,
Uint8Array, Unknown,
Buffer, ClassInstance, Function, JavaScriptClassExt, JsObjectValue, JsValue, ObjectFinalize,
This, Uint8Array, Unknown,
},
Env, Property, PropertyAttributes, Result,
};
@ -561,3 +561,30 @@ impl ThingList {
Thing
}
}
#[napi(
ts_return_type = r#"typeof DynamicRustClass\n\nclass DynamicRustClass {
constructor(value: number)
rustMethod(): number
}"#
)]
pub fn define_class(env: &Env) -> Result<Function> {
env.define_class(
"DynamicRustClass",
rust_class_constructor_c_callback,
&[Property::new()
.with_utf8_name("rustMethod")?
.with_method(rust_class_method_c_callback)],
)
}
#[napi(no_export)]
fn rust_class_constructor(value: i32, mut this: This) -> Result<()> {
this.set_named_property("dynamicValue", value)?;
Ok(())
}
#[napi(no_export)]
fn rust_class_method(this: This) -> Result<i32> {
this.get_named_property_unchecked::<i32>("dynamicValue")
}