1use std::ffi::{c_void, CStr};
2use std::ptr;
3
4use crate::Value;
5use crate::{bindgen_runtime::Unknown, check_status_or_throw, sys, Env};
6
7use super::{FromNapiValue, ToNapiValue};
8
9const GENERATOR_STATE_KEY: &CStr = c"[[GeneratorState]]";
10
11pub trait Generator {
14 type Yield: ToNapiValue;
15 type Next: FromNapiValue;
16 type Return: FromNapiValue;
17
18 fn next(&mut self, value: Option<Self::Next>) -> Option<Self::Yield>;
21
22 #[allow(unused_variables)]
23 fn complete(&mut self, value: Option<Self::Return>) -> Option<Self::Yield> {
26 None
27 }
28
29 #[allow(unused_variables)]
30 fn catch<'env>(
33 &'env mut self,
34 env: Env,
35 value: Unknown<'env>,
36 ) -> Result<Option<Self::Yield>, Unknown<'env>> {
37 Err(value)
38 }
39}
40
41impl<'env, T: Generator + 'env> ScopedGenerator<'env> for T {
42 type Yield = T::Yield;
43 type Next = T::Next;
44 type Return = T::Return;
45
46 fn next(&mut self, _: &'env Env, value: Option<Self::Next>) -> Option<Self::Yield> {
47 T::next(self, value)
48 }
49
50 fn complete(&mut self, value: Option<Self::Return>) -> Option<Self::Yield> {
51 T::complete(self, value)
52 }
53
54 fn catch(
55 &'env mut self,
56 env: &'env Env,
57 value: Unknown<'env>,
58 ) -> Result<Option<Self::Yield>, Unknown<'env>> {
59 T::catch(self, Env::from_raw(env.0), value)
60 }
61}
62
63pub trait ScopedGenerator<'env> {
64 type Yield: ToNapiValue + 'env;
65 type Next: FromNapiValue;
66 type Return: FromNapiValue;
67
68 fn next(&mut self, env: &'env Env, value: Option<Self::Next>) -> Option<Self::Yield>;
71
72 #[allow(unused_variables)]
73 fn complete(&mut self, value: Option<Self::Return>) -> Option<Self::Yield> {
76 None
77 }
78
79 #[allow(unused_variables)]
80 fn catch(
83 &'env mut self,
84 env: &'env Env,
85 value: Unknown<'env>,
86 ) -> Result<Option<Self::Yield>, Unknown<'env>> {
87 Err(value)
88 }
89}
90
91#[doc(hidden)]
92#[allow(clippy::not_unsafe_ptr_arg_deref)]
93pub unsafe fn create_iterator<'a, T: ScopedGenerator<'a> + 'a>(
94 env: sys::napi_env,
95 instance: sys::napi_value,
96 generator_ptr: *mut T,
97) {
98 let mut global = ptr::null_mut();
99 check_status_or_throw!(
100 env,
101 sys::napi_get_global(env, &mut global),
102 "Get global object failed",
103 );
104
105 let mut symbol_object = ptr::null_mut();
106 check_status_or_throw!(
107 env,
108 sys::napi_get_named_property(env, global, c"Symbol".as_ptr().cast(), &mut symbol_object),
109 "Get global object failed",
110 );
111
112 let mut iterator_symbol = ptr::null_mut();
113 check_status_or_throw!(
114 env,
115 sys::napi_get_named_property(
116 env,
117 symbol_object,
118 c"iterator".as_ptr().cast(),
119 &mut iterator_symbol,
120 ),
121 "Get Symbol.iterator failed",
122 );
123
124 let mut next_function = ptr::null_mut();
125 check_status_or_throw!(
126 env,
127 sys::napi_create_function(
128 env,
129 c"next".as_ptr().cast(),
130 4,
131 Some(generator_next::<T>),
132 generator_ptr as *mut c_void,
133 &mut next_function,
134 ),
135 "Create next function failed"
136 );
137
138 let mut return_function = ptr::null_mut();
139 check_status_or_throw!(
140 env,
141 sys::napi_create_function(
142 env,
143 c"return".as_ptr().cast(),
144 6,
145 Some(generator_return::<T>),
146 generator_ptr as *mut c_void,
147 &mut return_function,
148 ),
149 "Create return function failed"
150 );
151
152 let mut throw_function = ptr::null_mut();
153 check_status_or_throw!(
154 env,
155 sys::napi_create_function(
156 env,
157 c"throw".as_ptr().cast(),
158 5,
159 Some(generator_throw::<T>),
160 generator_ptr as *mut c_void,
161 &mut throw_function,
162 ),
163 "Create throw function failed"
164 );
165
166 check_status_or_throw!(
167 env,
168 sys::napi_set_named_property(env, instance, c"next".as_ptr().cast(), next_function,),
169 "Set next function on Generator object failed"
170 );
171
172 check_status_or_throw!(
173 env,
174 sys::napi_set_named_property(env, instance, c"return".as_ptr().cast(), return_function),
175 "Set return function on Generator object failed"
176 );
177
178 check_status_or_throw!(
179 env,
180 sys::napi_set_named_property(env, instance, c"throw".as_ptr().cast(), throw_function),
181 "Set throw function on Generator object failed"
182 );
183
184 let mut generator_state = ptr::null_mut();
185 check_status_or_throw!(
186 env,
187 sys::napi_get_boolean(env, false, &mut generator_state),
188 "Create generator state failed"
189 );
190
191 let properties = [sys::napi_property_descriptor {
192 utf8name: GENERATOR_STATE_KEY.as_ptr().cast(),
193 name: ptr::null_mut(),
194 method: None,
195 getter: None,
196 setter: None,
197 value: generator_state,
198 attributes: sys::PropertyAttributes::writable,
199 data: ptr::null_mut(),
200 }];
201
202 check_status_or_throw!(
203 env,
204 sys::napi_define_properties(env, instance, 1, properties.as_ptr()),
205 "Define properties on Generator object failed"
206 );
207
208 let mut generator_function = ptr::null_mut();
209 check_status_or_throw!(
210 env,
211 sys::napi_create_function(
212 env,
213 c"Iterator".as_ptr().cast(),
214 8,
215 Some(symbol_generator::<T>),
216 generator_ptr as *mut c_void,
217 &mut generator_function,
218 ),
219 "Create iterator function failed",
220 );
221
222 check_status_or_throw!(
223 env,
224 sys::napi_set_property(env, instance, iterator_symbol, generator_function),
225 "Failed to set Symbol.iterator on class instance",
226 );
227
228 let mut iterator_ctor = ptr::null_mut();
229 check_status_or_throw!(
230 env,
231 sys::napi_get_named_property(env, global, c"Iterator".as_ptr().cast(), &mut iterator_ctor,),
232 "Get Global.Iterator failed",
233 );
234
235 let mut iterator_ctor_type = 0;
236 check_status_or_throw!(
237 env,
238 sys::napi_typeof(env, iterator_ctor, &mut iterator_ctor_type),
239 "Get Global.Iterator type failed",
240 );
241
242 if iterator_ctor_type == sys::ValueType::napi_function {
243 let mut iterator_proto = ptr::null_mut();
244 check_status_or_throw!(
245 env,
246 sys::napi_get_named_property(
247 env,
248 iterator_ctor,
249 c"prototype".as_ptr().cast(),
250 &mut iterator_proto,
251 ),
252 "Failed to get Iterator.prototype",
253 );
254
255 let mut object_ctor = ptr::null_mut();
256 check_status_or_throw!(
257 env,
258 sys::napi_get_named_property(env, global, c"Object".as_ptr().cast(), &mut object_ctor),
259 "Failed to get Object constructor"
260 );
261
262 let mut set_prototype_function = ptr::null_mut();
263 check_status_or_throw!(
264 env,
265 sys::napi_get_named_property(
266 env,
267 object_ctor,
268 c"setPrototypeOf".as_ptr().cast(),
269 &mut set_prototype_function,
270 ),
271 "Failed to get Object.setPrototypeOf"
272 );
273
274 let mut argv = [instance, iterator_proto];
275 check_status_or_throw!(
276 env,
277 sys::napi_call_function(
278 env,
279 object_ctor,
280 set_prototype_function,
281 2,
282 argv.as_mut_ptr(),
283 ptr::null_mut(),
284 ),
285 "Failed to set prototype on object"
286 );
287 }
288}
289
290#[doc(hidden)]
291pub unsafe extern "C" fn symbol_generator<'a, T: ScopedGenerator<'a> + 'a>(
292 env: sys::napi_env,
293 info: sys::napi_callback_info,
294) -> sys::napi_value {
295 let mut this = ptr::null_mut();
296 let mut argv: [sys::napi_value; 1] = [ptr::null_mut()];
297 let mut argc = 0;
298 let mut generator_ptr = ptr::null_mut();
299 check_status_or_throw!(
300 env,
301 unsafe {
302 sys::napi_get_cb_info(
303 env,
304 info,
305 &mut argc,
306 argv.as_mut_ptr(),
307 &mut this,
308 &mut generator_ptr,
309 )
310 },
311 "Get callback info from generator function failed"
312 );
313
314 this
315}
316
317extern "C" fn generator_next<'a, T: ScopedGenerator<'a> + 'a>(
318 env: sys::napi_env,
319 info: sys::napi_callback_info,
320) -> sys::napi_value {
321 let mut this = ptr::null_mut();
322 let mut argv: [sys::napi_value; 1] = [ptr::null_mut()];
323 let mut argc = 1;
324 let mut generator_ptr = ptr::null_mut();
325 check_status_or_throw!(
326 env,
327 unsafe {
328 sys::napi_get_cb_info(
329 env,
330 info,
331 &mut argc,
332 argv.as_mut_ptr(),
333 &mut this,
334 &mut generator_ptr,
335 )
336 },
337 "Get callback info from generator function failed"
338 );
339 let mut generator_state = ptr::null_mut();
340 check_status_or_throw!(
341 env,
342 unsafe {
343 sys::napi_get_named_property(
344 env,
345 this,
346 GENERATOR_STATE_KEY.as_ptr().cast(),
347 &mut generator_state,
348 )
349 },
350 "Get generator state failed"
351 );
352 let mut completed = false;
353 check_status_or_throw!(
354 env,
355 unsafe { sys::napi_get_value_bool(env, generator_state, &mut completed) },
356 "Get generator state failed"
357 );
358 let mut result = std::ptr::null_mut();
359 check_status_or_throw!(
360 env,
361 unsafe { sys::napi_create_object(env, &mut result) },
362 "Failed to create iterator result object",
363 );
364 if !completed {
365 let g = unsafe { Box::leak(Box::from_raw(generator_ptr as *mut T)) };
366 let item = if argc == 0 {
367 g.next(
368 unsafe { std::mem::transmute::<&Env, &'a Env>(&Env::from_raw(env)) },
370 None,
371 )
372 } else {
373 g.next(
374 unsafe { std::mem::transmute::<&Env, &'a Env>(&Env::from_raw(env)) },
376 match unsafe { T::Next::from_napi_value(env, argv[0]) } {
377 Ok(input) => Some(input),
378 Err(e) => {
379 unsafe {
380 sys::napi_throw_error(
381 env,
382 format!("{}", e.status).as_ptr().cast(),
383 e.reason.as_ptr().cast(),
384 )
385 };
386 None
387 }
388 },
389 )
390 };
391
392 if let Some(value) = item {
393 set_generator_value(env, result, value);
394 } else {
395 completed = true;
396 }
397 }
398 let mut completed_value = ptr::null_mut();
399 check_status_or_throw!(
400 env,
401 unsafe { sys::napi_get_boolean(env, completed, &mut completed_value) },
402 "Failed to create completed value"
403 );
404 check_status_or_throw!(
405 env,
406 unsafe { sys::napi_set_named_property(env, result, c"done".as_ptr().cast(), completed_value,) },
407 "Failed to set iterator result done",
408 );
409
410 result
411}
412
413extern "C" fn generator_return<'a, T: ScopedGenerator<'a> + 'a>(
414 env: sys::napi_env,
415 info: sys::napi_callback_info,
416) -> sys::napi_value {
417 let mut this = ptr::null_mut();
418 let mut argv: [sys::napi_value; 1] = [ptr::null_mut()];
419 let mut argc = 1;
420 let mut generator_ptr = ptr::null_mut();
421 check_status_or_throw!(
422 env,
423 unsafe {
424 sys::napi_get_cb_info(
425 env,
426 info,
427 &mut argc,
428 argv.as_mut_ptr(),
429 &mut this,
430 &mut generator_ptr,
431 )
432 },
433 "Get callback info from generator function failed"
434 );
435
436 let g = unsafe { Box::leak(Box::from_raw(generator_ptr as *mut T)) };
437 if argc == 0 {
438 g.complete(None);
439 } else {
440 g.complete(Some(
441 match unsafe { T::Return::from_napi_value(env, argv[0]) } {
442 Ok(input) => input,
443 Err(e) => {
444 unsafe {
445 sys::napi_throw_error(
446 env,
447 format!("{}", e.status).as_ptr().cast(),
448 e.reason.as_ptr().cast(),
449 )
450 };
451 return ptr::null_mut();
452 }
453 },
454 ));
455 }
456 let mut generator_state = ptr::null_mut();
457 check_status_or_throw!(
458 env,
459 unsafe { sys::napi_get_boolean(env, true, &mut generator_state) },
460 "Create generator state failed"
461 );
462 check_status_or_throw!(
463 env,
464 unsafe {
465 sys::napi_set_named_property(
466 env,
467 this,
468 GENERATOR_STATE_KEY.as_ptr().cast(),
469 generator_state,
470 )
471 },
472 "Get generator state failed"
473 );
474 let mut result = std::ptr::null_mut();
475 check_status_or_throw!(
476 env,
477 unsafe { sys::napi_create_object(env, &mut result) },
478 "Failed to create iterator result object",
479 );
480 if argc > 0 {
481 check_status_or_throw!(
482 env,
483 unsafe { sys::napi_set_named_property(env, result, c"value".as_ptr().cast(), argv[0],) },
484 "Failed to set iterator result value",
485 );
486 }
487 check_status_or_throw!(
488 env,
489 unsafe {
490 sys::napi_set_named_property(
491 env,
492 result,
493 c"done".as_ptr() as *const std::os::raw::c_char,
494 generator_state,
495 )
496 },
497 "Failed to set iterator result done",
498 );
499
500 result
501}
502
503extern "C" fn generator_throw<'a, T: ScopedGenerator<'a> + 'a>(
504 env: sys::napi_env,
505 info: sys::napi_callback_info,
506) -> sys::napi_value {
507 let mut this = ptr::null_mut();
508 let mut argv: [sys::napi_value; 1] = [ptr::null_mut()];
509 let mut argc = 1;
510 let mut generator_ptr = ptr::null_mut();
511 check_status_or_throw!(
512 env,
513 unsafe {
514 sys::napi_get_cb_info(
515 env,
516 info,
517 &mut argc,
518 argv.as_mut_ptr(),
519 &mut this,
520 &mut generator_ptr,
521 )
522 },
523 "Get callback info from generator function failed"
524 );
525
526 let g = unsafe { Box::leak(Box::from_raw(generator_ptr as *mut T)) };
527 let catch_result = if argc == 0 {
528 let mut undefined = ptr::null_mut();
529 check_status_or_throw!(
530 env,
531 unsafe { sys::napi_get_undefined(env, &mut undefined) },
532 "Get undefined failed"
533 );
534 g.catch(
535 unsafe { std::mem::transmute::<&Env, &'a Env>(&Env::from_raw(env)) },
537 Unknown(
538 Value {
539 env,
540 value: undefined,
541 value_type: crate::ValueType::Unknown,
542 },
543 std::marker::PhantomData,
544 ),
545 )
546 } else {
547 g.catch(
548 unsafe { std::mem::transmute::<&Env, &'a Env>(&Env::from_raw(env)) },
550 Unknown(
551 Value {
552 env,
553 value: argv[0],
554 value_type: crate::ValueType::Unknown,
555 },
556 std::marker::PhantomData,
557 ),
558 )
559 };
560 let mut result = ptr::null_mut();
561 check_status_or_throw!(
562 env,
563 unsafe { sys::napi_create_object(env, &mut result) },
564 "Failed to create iterator result object",
565 );
566 let mut generator_state = ptr::null_mut();
567 let mut generator_state_value = false;
568 match catch_result {
569 Err(e) => {
570 generator_state_value = true;
571 check_status_or_throw!(
572 env,
573 unsafe { sys::napi_get_boolean(env, generator_state_value, &mut generator_state) },
574 "Create generator state failed"
575 );
576 check_status_or_throw!(
577 env,
578 unsafe {
579 sys::napi_set_named_property(
580 env,
581 this,
582 GENERATOR_STATE_KEY.as_ptr().cast(),
583 generator_state,
584 )
585 },
586 "Get generator state failed"
587 );
588 let throw_status = unsafe { sys::napi_throw(env, e.0.value) };
589 debug_assert!(
590 throw_status == sys::Status::napi_ok,
591 "Failed to throw error {}",
592 crate::Status::from(throw_status)
593 );
594 return ptr::null_mut();
595 }
596 Ok(Some(v)) => {
597 set_generator_value(env, result, v);
598 }
599 Ok(None) => {
600 generator_state_value = true;
601 }
602 }
603 check_status_or_throw!(
604 env,
605 unsafe { sys::napi_get_boolean(env, generator_state_value, &mut generator_state) },
606 "Create generator state failed"
607 );
608 check_status_or_throw!(
609 env,
610 unsafe {
611 sys::napi_set_named_property(
612 env,
613 this,
614 GENERATOR_STATE_KEY.as_ptr().cast(),
615 generator_state,
616 )
617 },
618 "Get generator state failed"
619 );
620 check_status_or_throw!(
621 env,
622 unsafe { sys::napi_set_named_property(env, result, c"done".as_ptr().cast(), generator_state) },
623 "Get generator state failed"
624 );
625
626 result
627}
628
629fn set_generator_value<V: ToNapiValue>(env: sys::napi_env, result: sys::napi_value, value: V) {
630 match unsafe { ToNapiValue::to_napi_value(env, value) } {
631 Ok(val) => {
632 check_status_or_throw!(
633 env,
634 unsafe { sys::napi_set_named_property(env, result, c"value".as_ptr().cast(), val,) },
635 "Failed to set iterator result value",
636 );
637 }
638 Err(e) => {
639 unsafe {
640 sys::napi_throw_error(
641 env,
642 format!("{}", e.status).as_ptr().cast(),
643 e.reason.as_ptr().cast(),
644 )
645 };
646 }
647 }
648}