fix(napi): missing iterator implementation from class factory
This commit is contained in:
parent
57ea8dc8f3
commit
47fcc8501a
7 changed files with 192 additions and 75 deletions
|
@ -294,7 +294,13 @@ impl NapiFn {
|
||||||
}
|
}
|
||||||
} else if self.kind == FnKind::Factory {
|
} else if self.kind == FnKind::Factory {
|
||||||
if self.is_ret_result {
|
if self.is_ret_result {
|
||||||
|
if self.parent_is_generator {
|
||||||
|
quote! { cb.generator_factory(#js_name, #ret?) }
|
||||||
|
} else {
|
||||||
quote! { cb.factory(#js_name, #ret?) }
|
quote! { cb.factory(#js_name, #ret?) }
|
||||||
|
}
|
||||||
|
} else if self.parent_is_generator {
|
||||||
|
quote! { cb.generator_factory(#js_name, #ret) }
|
||||||
} else {
|
} else {
|
||||||
quote! { cb.factory(#js_name, #ret) }
|
quote! { cb.factory(#js_name, #ret) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,43 +113,59 @@ impl<const N: usize> CallbackInfo<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn factory<T: 'static>(&self, js_name: &str, obj: T) -> Result<sys::napi_value> {
|
pub fn factory<T: 'static>(&self, js_name: &str, obj: T) -> Result<sys::napi_value> {
|
||||||
|
self._factory(js_name, obj).map(|(value, _)| value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generator_factory<T: Generator + 'static>(
|
||||||
|
&self,
|
||||||
|
js_name: &str,
|
||||||
|
obj: T,
|
||||||
|
) -> Result<sys::napi_value> {
|
||||||
|
let (instance, generator_ptr) = self._factory(js_name, obj)?;
|
||||||
|
crate::__private::create_iterator(self.env, instance, generator_ptr);
|
||||||
|
Ok(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _factory<T: 'static>(&self, js_name: &str, obj: T) -> Result<(sys::napi_value, *mut T)> {
|
||||||
let this = self.this();
|
let this = self.this();
|
||||||
let mut instance = ptr::null_mut();
|
let mut instance = ptr::null_mut();
|
||||||
unsafe {
|
|
||||||
let inner = ___CALL_FROM_FACTORY.get_or_default();
|
let inner = ___CALL_FROM_FACTORY.get_or_default();
|
||||||
inner.store(true, Ordering::Relaxed);
|
inner.store(true, Ordering::Relaxed);
|
||||||
let status = sys::napi_new_instance(self.env, this, 0, ptr::null_mut(), &mut instance);
|
let status =
|
||||||
|
unsafe { sys::napi_new_instance(self.env, this, 0, ptr::null_mut(), &mut instance) };
|
||||||
inner.store(false, Ordering::Relaxed);
|
inner.store(false, Ordering::Relaxed);
|
||||||
// Error thrown in `constructor`
|
// Error thrown in `constructor`
|
||||||
if status == sys::Status::napi_pending_exception {
|
if status == sys::Status::napi_pending_exception {
|
||||||
let mut exception = ptr::null_mut();
|
let mut exception = ptr::null_mut();
|
||||||
sys::napi_get_and_clear_last_exception(self.env, &mut exception);
|
unsafe { sys::napi_get_and_clear_last_exception(self.env, &mut exception) };
|
||||||
sys::napi_throw(self.env, exception);
|
unsafe { sys::napi_throw(self.env, exception) };
|
||||||
return Ok(ptr::null_mut());
|
return Ok((ptr::null_mut(), ptr::null_mut()));
|
||||||
}
|
}
|
||||||
let obj = Box::new(obj);
|
let obj = Box::new(obj);
|
||||||
let initial_finalize: Box<dyn FnOnce()> = Box::new(|| {});
|
let initial_finalize: Box<dyn FnOnce()> = Box::new(|| {});
|
||||||
let finalize_callbacks_ptr =
|
let finalize_callbacks_ptr = Rc::into_raw(Rc::new(Cell::new(Box::into_raw(initial_finalize))));
|
||||||
Rc::into_raw(Rc::new(Cell::new(Box::into_raw(initial_finalize))));
|
|
||||||
let mut object_ref = ptr::null_mut();
|
let mut object_ref = ptr::null_mut();
|
||||||
let value_ref = Box::into_raw(obj) as *mut c_void;
|
let value_ref = Box::into_raw(obj);
|
||||||
check_status!(
|
check_status!(
|
||||||
|
unsafe {
|
||||||
sys::napi_wrap(
|
sys::napi_wrap(
|
||||||
self.env,
|
self.env,
|
||||||
instance,
|
instance,
|
||||||
value_ref,
|
value_ref as *mut c_void,
|
||||||
Some(raw_finalize_unchecked::<T>),
|
Some(raw_finalize_unchecked::<T>),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
&mut object_ref
|
&mut object_ref,
|
||||||
),
|
)
|
||||||
|
},
|
||||||
"Failed to initialize class `{}`",
|
"Failed to initialize class `{}`",
|
||||||
js_name,
|
js_name,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Reference::<T>::add_ref(value_ref, (value_ref, object_ref, finalize_callbacks_ptr));
|
Reference::<T>::add_ref(
|
||||||
};
|
value_ref as *mut c_void,
|
||||||
|
(value_ref as *mut c_void, object_ref, finalize_callbacks_ptr),
|
||||||
Ok(instance)
|
);
|
||||||
|
Ok((instance, value_ref))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap_borrow_mut<T>(&mut self) -> Result<&'static mut T>
|
pub fn unwrap_borrow_mut<T>(&mut self) -> Result<&'static mut T>
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
import test from 'ava'
|
import test from 'ava'
|
||||||
|
|
||||||
import { Fib } from '../index'
|
import { Fib, Fib2, Fib3 } from '../index'
|
||||||
|
|
||||||
test('should be able to stop a generator', (t) => {
|
for (const [index, factory] of [
|
||||||
const fib = new Fib()
|
() => new Fib(),
|
||||||
|
() => Fib2.create(0),
|
||||||
|
() => new Fib3(0, 1),
|
||||||
|
].entries()) {
|
||||||
|
test(`should be able to stop a generator #${index}`, (t) => {
|
||||||
|
const fib = factory()
|
||||||
const gen = fib[Symbol.iterator]
|
const gen = fib[Symbol.iterator]
|
||||||
t.is(typeof gen, 'function')
|
t.is(typeof gen, 'function')
|
||||||
const iterator = gen()
|
const iterator = gen()
|
||||||
|
@ -27,8 +32,8 @@ test('should be able to stop a generator', (t) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should be able to throw to generator', (t) => {
|
test(`should be able to throw to generator #${index}`, (t) => {
|
||||||
const fib = new Fib()
|
const fib = factory()
|
||||||
const gen = fib[Symbol.iterator]
|
const gen = fib[Symbol.iterator]
|
||||||
t.is(typeof gen, 'function')
|
t.is(typeof gen, 'function')
|
||||||
const iterator = gen()
|
const iterator = gen()
|
||||||
|
@ -49,3 +54,4 @@ test('should be able to throw to generator', (t) => {
|
||||||
done: true,
|
done: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -268,6 +268,16 @@ Generated by [AVA](https://avajs.dev).
|
||||||
[Symbol.iterator](): Iterator<number, void, number>␊
|
[Symbol.iterator](): Iterator<number, void, number>␊
|
||||||
constructor()␊
|
constructor()␊
|
||||||
}␊
|
}␊
|
||||||
|
export class Fib2 {␊
|
||||||
|
[Symbol.iterator](): Iterator<number, void, number>␊
|
||||||
|
static create(seed: number): Fib2␊
|
||||||
|
}␊
|
||||||
|
export class Fib3 {␊
|
||||||
|
current: number␊
|
||||||
|
next: number␊
|
||||||
|
constructor(current: number, next: number)␊
|
||||||
|
[Symbol.iterator](): Iterator<number, void, number>␊
|
||||||
|
}␊
|
||||||
export class JsRepo {␊
|
export class JsRepo {␊
|
||||||
constructor(dir: string)␊
|
constructor(dir: string)␊
|
||||||
remote(): JsRemote␊
|
remote(): JsRemote␊
|
||||||
|
|
Binary file not shown.
10
examples/napi/index.d.ts
vendored
10
examples/napi/index.d.ts
vendored
|
@ -258,6 +258,16 @@ export class Fib {
|
||||||
[Symbol.iterator](): Iterator<number, void, number>
|
[Symbol.iterator](): Iterator<number, void, number>
|
||||||
constructor()
|
constructor()
|
||||||
}
|
}
|
||||||
|
export class Fib2 {
|
||||||
|
[Symbol.iterator](): Iterator<number, void, number>
|
||||||
|
static create(seed: number): Fib2
|
||||||
|
}
|
||||||
|
export class Fib3 {
|
||||||
|
current: number
|
||||||
|
next: number
|
||||||
|
constructor(current: number, next: number)
|
||||||
|
[Symbol.iterator](): Iterator<number, void, number>
|
||||||
|
}
|
||||||
export class JsRepo {
|
export class JsRepo {
|
||||||
constructor(dir: string)
|
constructor(dir: string)
|
||||||
remote(): JsRemote
|
remote(): JsRemote
|
||||||
|
|
|
@ -40,3 +40,72 @@ impl Fib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(iterator)]
|
||||||
|
pub struct Fib2 {
|
||||||
|
current: u32,
|
||||||
|
next: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
impl Generator for Fib2 {
|
||||||
|
type Yield = u32;
|
||||||
|
type Next = i32;
|
||||||
|
type Return = ();
|
||||||
|
|
||||||
|
fn next(&mut self, value: Option<Self::Next>) -> Option<Self::Yield> {
|
||||||
|
match value {
|
||||||
|
Some(n) => {
|
||||||
|
self.current = n as u32;
|
||||||
|
self.next = n as u32 + 1;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let next = self.next;
|
||||||
|
let current = self.current;
|
||||||
|
self.current = next;
|
||||||
|
self.next = current + next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(self.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
impl Fib2 {
|
||||||
|
#[napi(factory)]
|
||||||
|
pub fn create(seed: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
current: seed,
|
||||||
|
next: seed + 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(iterator, constructor)]
|
||||||
|
pub struct Fib3 {
|
||||||
|
pub current: u32,
|
||||||
|
pub next: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
impl Generator for Fib3 {
|
||||||
|
type Yield = u32;
|
||||||
|
type Next = i32;
|
||||||
|
type Return = ();
|
||||||
|
|
||||||
|
fn next(&mut self, value: Option<Self::Next>) -> Option<Self::Yield> {
|
||||||
|
match value {
|
||||||
|
Some(n) => {
|
||||||
|
self.current = n as u32;
|
||||||
|
self.next = n as u32 + 1;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let next = self.next;
|
||||||
|
let current = self.current;
|
||||||
|
self.current = next;
|
||||||
|
self.next = current + next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(self.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue