fix(napi-derive): return instance from non-default constructor class

Fix https://github.com/napi-rs/napi-rs/issues/933
This commit is contained in:
LongYinan 2021-12-24 18:46:10 +08:00
parent c25cfc5773
commit e6a30ffcca
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
7 changed files with 76 additions and 2 deletions

View file

@ -1,3 +1,5 @@
import { platform } from 'os'
import test from 'ava' import test from 'ava'
import { parseTriple, getDefaultTargetTriple } from '../parse-triple' import { parseTriple, getDefaultTargetTriple } from '../parse-triple'
@ -121,7 +123,10 @@ for (const triple of triples) {
}) })
} }
test('should parse default triple from rustup show active', (t) => { const MaybeTest =
process.arch !== 'x64' && platform() === 'linux' ? test.skip : test
MaybeTest('should parse default triple from rustup show active', (t) => {
t.deepEqual( t.deepEqual(
getDefaultTargetTriple( getDefaultTargetTriple(
`x86_64-unknown-linux-gnu (directory override for '/home/runner/work/fast-escape/fast-escape')`, `x86_64-unknown-linux-gnu (directory override for '/home/runner/work/fast-escape/fast-escape')`,

View file

@ -153,7 +153,10 @@ impl NapiStruct {
fn gen_napi_value_map_impl(&self) -> TokenStream { fn gen_napi_value_map_impl(&self) -> TokenStream {
match self.kind { match self.kind {
NapiStructKind::None => gen_napi_value_map_impl(&self.name, quote! {}), NapiStructKind::None => gen_napi_value_map_impl(
&self.name,
self.gen_to_napi_value_ctor_impl_for_non_default_constructor_struct(),
),
NapiStructKind::Constructor => { NapiStructKind::Constructor => {
gen_napi_value_map_impl(&self.name, self.gen_to_napi_value_ctor_impl()) gen_napi_value_map_impl(&self.name, self.gen_to_napi_value_ctor_impl())
} }
@ -161,6 +164,42 @@ impl NapiStruct {
} }
} }
fn gen_to_napi_value_ctor_impl_for_non_default_constructor_struct(&self) -> TokenStream {
let name = &self.name;
let js_name_str = format!("{}\0", &self.js_name);
quote! {
impl napi::bindgen_prelude::ToNapiValue for #name {
unsafe fn to_napi_value(
env: napi::bindgen_prelude::sys::napi_env, val: #name
) -> napi::bindgen_prelude::Result<napi::bindgen_prelude::sys::napi_value> {
if let Some(ctor_ref) = napi::bindgen_prelude::get_class_constructor(#js_name_str) {
let mut ctor = std::ptr::null_mut();
napi::bindgen_prelude::check_status!(
napi::bindgen_prelude::sys::napi_get_reference_value(env, ctor_ref, &mut ctor),
"Failed to get constructor of class `{}`",
#js_name_str
)?;
let mut result = std::ptr::null_mut();
napi::bindgen_prelude::___CALL_FROM_FACTORY.store(true, std::sync::atomic::Ordering::Relaxed);
napi::bindgen_prelude::check_status!(
napi::bindgen_prelude::sys::napi_new_instance(env, ctor, 0, std::ptr::null_mut(), &mut result),
"Failed to construct class `{}`",
#js_name_str
)?;
napi::bindgen_prelude::___CALL_FROM_FACTORY.store(false, std::sync::atomic::Ordering::Relaxed);
Ok(result)
} else {
Err(napi::bindgen_prelude::Error::new(
napi::bindgen_prelude::Status::InvalidArg, format!("Failed to get constructor of class `{}`", #js_name_str))
)
}
}
}
}
}
fn gen_to_napi_value_ctor_impl(&self) -> TokenStream { fn gen_to_napi_value_ctor_impl(&self) -> TokenStream {
let name = &self.name; let name = &self.name;
let js_name_str = format!("{}\0", &self.js_name); let js_name_str = format!("{}\0", &self.js_name);

View file

@ -145,11 +145,16 @@ Generated by [AVA](https://avajs.dev).
/** This is static... */␊ /** This is static... */␊
static getDogKind(): Kind␊ static getDogKind(): Kind␊
returnOtherClass(): Dog␊ returnOtherClass(): Dog␊
returnOtherClassWithCustomConstructor(): Bird␊
}␊ }␊
export class Dog {␊ export class Dog {␊
name: string␊ name: string␊
constructor(name: string)␊ constructor(name: string)␊
}␊ }␊
export class Bird {␊
name: string␊
constructor(name: string)␊
}␊
/** Smoking test for type generation */␊ /** Smoking test for type generation */␊
export class Blake2BHasher {␊ export class Blake2BHasher {␊
static withKey(key: Blake2bKey): Blake2BHasher␊ static withKey(key: Blake2bKey): Blake2BHasher␊

View file

@ -70,6 +70,7 @@ import {
returnNull, returnNull,
returnUndefined, returnUndefined,
Dog, Dog,
Bird,
} from '../' } from '../'
test('export const', (t) => { test('export const', (t) => {
@ -127,6 +128,7 @@ test('class', (t) => {
dog.name = '可乐' dog.name = '可乐'
t.is(dog.name, '可乐') t.is(dog.name, '可乐')
t.deepEqual(dog.returnOtherClass(), new Dog('Doge')) t.deepEqual(dog.returnOtherClass(), new Dog('Doge'))
t.deepEqual(dog.returnOtherClassWithCustomConstructor(), new Bird('parrot'))
}) })
test('class factory', (t) => { test('class factory', (t) => {

View file

@ -135,11 +135,16 @@ export class Animal {
/** This is static... */ /** This is static... */
static getDogKind(): Kind static getDogKind(): Kind
returnOtherClass(): Dog returnOtherClass(): Dog
returnOtherClassWithCustomConstructor(): Bird
} }
export class Dog { export class Dog {
name: string name: string
constructor(name: string) constructor(name: string)
} }
export class Bird {
name: string
constructor(name: string)
}
/** Smoking test for type generation */ /** Smoking test for type generation */
export class Blake2BHasher { export class Blake2BHasher {
static withKey(key: Blake2bKey): Blake2BHasher static withKey(key: Blake2bKey): Blake2BHasher

View file

@ -67,6 +67,11 @@ impl Animal {
name: "Doge".to_owned(), name: "Doge".to_owned(),
} }
} }
#[napi]
pub fn return_other_class_with_custom_constructor(&self) -> Bird {
Bird::new("parrot".to_owned())
}
} }
#[napi(constructor)] #[napi(constructor)]
@ -74,6 +79,19 @@ pub struct Dog {
pub name: String, pub name: String,
} }
#[napi]
pub struct Bird {
pub name: String,
}
#[napi]
impl Bird {
#[napi(constructor)]
pub fn new(name: String) -> Self {
Bird { name }
}
}
/// Smoking test for type generation /// Smoking test for type generation
#[napi] #[napi]
#[repr(transparent)] #[repr(transparent)]