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