fix(napi): missing iterator implementation from class factory

This commit is contained in:
LongYinan 2022-05-10 21:46:16 +08:00
parent 57ea8dc8f3
commit 47fcc8501a
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
7 changed files with 192 additions and 75 deletions

View file

@ -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) }
} }

View file

@ -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>

View file

@ -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,
}) })
}) })
}

View file

@ -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␊

View file

@ -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

View file

@ -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)
}
}