1#![allow(clippy::single_component_path_imports)]
2
3use std::convert::Into;
4use std::ffi::CString;
5use std::marker::PhantomData;
6use std::os::raw::c_void;
7use std::ptr::null_mut;
8use std::ptr::{self};
9use std::sync::atomic::AtomicBool;
10use std::sync::atomic::AtomicPtr;
11use std::sync::atomic::Ordering;
12use std::sync::Arc;
13use std::sync::RwLock;
14use std::sync::RwLockWriteGuard;
15use std::sync::Weak;
16
17use libnode_sys;
18
19use crate::napi::bindgen_runtime::FromNapiValue;
20use crate::napi::bindgen_runtime::JsValuesTupleIntoVec;
21use crate::napi::bindgen_runtime::ToNapiValue;
22use crate::napi::bindgen_runtime::TypeName;
23use crate::napi::bindgen_runtime::ValidateNapiValue;
24use crate::napi::check_status;
25use crate::napi::Env;
26use crate::napi::JsError;
27use crate::napi::JsUnknown;
28use crate::napi::Result;
29use crate::napi::Status;
30
31pub struct ThreadSafeCallContext<T: 'static> {
34 pub env: Env,
35 pub value: T,
36}
37
38#[repr(u8)]
39#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub enum ThreadsafeFunctionCallMode {
41 NonBlocking,
42 Blocking,
43}
44
45impl From<ThreadsafeFunctionCallMode> for libnode_sys::napi_threadsafe_function_call_mode {
46 fn from(value: ThreadsafeFunctionCallMode) -> Self {
47 match value {
48 ThreadsafeFunctionCallMode::Blocking => libnode_sys::ThreadsafeFunctionCallMode::blocking,
49 ThreadsafeFunctionCallMode::NonBlocking => {
50 libnode_sys::ThreadsafeFunctionCallMode::nonblocking
51 }
52 }
53 }
54}
55
56type_level_enum! {
57 pub enum ErrorStrategy {
101 CalleeHandled,
107
108 Fatal,
115 }
116}
117
118struct ThreadsafeFunctionHandle {
119 raw: AtomicPtr<libnode_sys::napi_threadsafe_function__>,
120 aborted: RwLock<bool>,
121 referred: AtomicBool,
122}
123
124impl ThreadsafeFunctionHandle {
125 fn new(raw: libnode_sys::napi_threadsafe_function) -> Arc<Self> {
127 Arc::new(Self {
128 raw: AtomicPtr::new(raw),
129 aborted: RwLock::new(false),
130 referred: AtomicBool::new(true),
131 })
132 }
133
134 fn with_read_aborted<RT, F>(
136 &self,
137 f: F,
138 ) -> RT
139 where
140 F: FnOnce(bool) -> RT,
141 {
142 let aborted_guard = self
143 .aborted
144 .read()
145 .expect("Threadsafe Function aborted lock failed");
146 f(*aborted_guard)
147 }
148
149 fn with_write_aborted<RT, F>(
151 &self,
152 f: F,
153 ) -> RT
154 where
155 F: FnOnce(RwLockWriteGuard<bool>) -> RT,
156 {
157 let aborted_guard = self
158 .aborted
159 .write()
160 .expect("Threadsafe Function aborted lock failed");
161 f(aborted_guard)
162 }
163
164 #[allow(clippy::arc_with_non_send_sync)]
165 fn null() -> Arc<Self> {
166 Self::new(null_mut())
167 }
168
169 fn get_raw(&self) -> libnode_sys::napi_threadsafe_function {
170 self.raw.load(Ordering::SeqCst)
171 }
172
173 fn set_raw(
174 &self,
175 raw: libnode_sys::napi_threadsafe_function,
176 ) {
177 self.raw.store(raw, Ordering::SeqCst)
178 }
179}
180
181impl Drop for ThreadsafeFunctionHandle {
182 fn drop(&mut self) {
183 self.with_read_aborted(|aborted| {
184 if !aborted {
185 let release_status = unsafe {
186 libnode_sys::napi_release_threadsafe_function(
187 self.get_raw(),
188 libnode_sys::ThreadsafeFunctionReleaseMode::release,
189 )
190 };
191 assert!(
192 release_status == libnode_sys::Status::napi_ok,
193 "Threadsafe Function release failed {}",
194 Status::from(release_status)
195 );
196 }
197 })
198 }
199}
200
201#[repr(u8)]
202enum ThreadsafeFunctionCallVariant {
203 Direct,
204 WithCallback,
205}
206
207struct ThreadsafeFunctionCallJsBackData<T> {
208 data: T,
209 call_variant: ThreadsafeFunctionCallVariant,
210 callback: Box<dyn FnOnce(Result<JsUnknown>) -> Result<()>>,
211}
212
213pub struct ThreadsafeFunction<T: 'static, ES: ErrorStrategy::T = ErrorStrategy::CalleeHandled> {
263 handle: Arc<ThreadsafeFunctionHandle>,
264 _phantom: PhantomData<(T, ES)>,
265}
266
267unsafe impl<T: 'static, ES: ErrorStrategy::T> Send for ThreadsafeFunction<T, ES> {}
268unsafe impl<T: 'static, ES: ErrorStrategy::T> Sync for ThreadsafeFunction<T, ES> {}
269
270impl<T: 'static, ES: ErrorStrategy::T> Clone for ThreadsafeFunction<T, ES> {
271 fn clone(&self) -> Self {
272 self.handle.with_read_aborted(|aborted| {
273 if aborted {
274 panic!("ThreadsafeFunction was aborted, can not clone it");
275 };
276
277 Self {
278 handle: self.handle.clone(),
279 _phantom: PhantomData,
280 }
281 })
282 }
283}
284
285impl<T: ToNapiValue> JsValuesTupleIntoVec for T {
286 #[allow(clippy::not_unsafe_ptr_arg_deref)]
287 fn into_vec(
288 self,
289 env: libnode_sys::napi_env,
290 ) -> Result<Vec<libnode_sys::napi_value>> {
291 Ok(vec![unsafe {
292 <T as ToNapiValue>::to_napi_value(env, self)?
293 }])
294 }
295}
296
297macro_rules! impl_js_value_tuple_to_vec {
298 ($($ident:ident),*) => {
299 impl<$($ident: ToNapiValue),*> JsValuesTupleIntoVec for ($($ident,)*) {
300 #[allow(clippy::not_unsafe_ptr_arg_deref)]
301 fn into_vec(self, env: libnode_sys::napi_env) -> Result<Vec<libnode_sys::napi_value>> {
302 #[allow(non_snake_case)]
303 let ($($ident,)*) = self;
304 Ok(vec![$(unsafe { <$ident as ToNapiValue>::to_napi_value(env, $ident)? }),*])
305 }
306 }
307 };
308}
309
310impl_js_value_tuple_to_vec!(A);
311impl_js_value_tuple_to_vec!(A, B);
312impl_js_value_tuple_to_vec!(A, B, C);
313impl_js_value_tuple_to_vec!(A, B, C, D);
314impl_js_value_tuple_to_vec!(A, B, C, D, E);
315impl_js_value_tuple_to_vec!(A, B, C, D, E, F);
316impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G);
317impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H);
318impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I);
319impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J);
320impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K);
321impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L);
322impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M);
323impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
324impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
325impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
326impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
327impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
328impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
329impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
330impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
331impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
332impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
333impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
334impl_js_value_tuple_to_vec!(
335 A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
336);
337impl_js_value_tuple_to_vec!(
338 A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
339);
340
341impl<T: JsValuesTupleIntoVec + 'static, ES: ErrorStrategy::T> FromNapiValue
342 for ThreadsafeFunction<T, ES>
343{
344 unsafe fn from_napi_value(
345 env: libnode_sys::napi_env,
346 napi_val: libnode_sys::napi_value,
347 ) -> Result<Self> {
348 Self::create(env, napi_val, 0, |ctx| ctx.value.into_vec(ctx.env.0))
349 }
350}
351
352impl<T: 'static, ES: ErrorStrategy::T> ThreadsafeFunction<T, ES> {
353 pub(crate) fn create<
356 V: ToNapiValue,
357 R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
358 >(
359 env: libnode_sys::napi_env,
360 func: libnode_sys::napi_value,
361 max_queue_size: usize,
362 callback: R,
363 ) -> Result<Self> {
364 let mut async_resource_name = ptr::null_mut();
365 let s = "napi_rs_threadsafe_function";
366 let len = s.len();
367 let s = CString::new(s)?;
368 check_status!(unsafe {
369 libnode_sys::napi_create_string_utf8(env, s.as_ptr(), len as isize, &mut async_resource_name)
370 })?;
371
372 let mut raw_tsfn = ptr::null_mut();
373 let callback_ptr = Box::into_raw(Box::new(callback));
374 let handle = ThreadsafeFunctionHandle::null();
375 check_status!(unsafe {
376 libnode_sys::napi_create_threadsafe_function(
377 env,
378 func,
379 ptr::null_mut(),
380 async_resource_name,
381 max_queue_size,
382 1,
383 Arc::downgrade(&handle).into_raw() as *mut c_void, Some(thread_finalize_cb::<T, V, R>),
385 callback_ptr.cast(),
386 Some(call_js_cb::<T, V, R, ES>),
387 &mut raw_tsfn,
388 )
389 })?;
390 handle.set_raw(raw_tsfn);
391
392 Ok(ThreadsafeFunction {
393 handle,
394 _phantom: PhantomData,
395 })
396 }
397
398 pub fn refer(
403 &mut self,
404 env: &Env,
405 ) -> Result<()> {
406 self.handle.with_read_aborted(|aborted| {
407 if !aborted && !self.handle.referred.load(Ordering::Relaxed) {
408 check_status!(unsafe {
409 libnode_sys::napi_ref_threadsafe_function(env.0, self.handle.get_raw())
410 })?;
411 self.handle.referred.store(true, Ordering::Relaxed);
412 }
413 Ok(())
414 })
415 }
416
417 pub fn unref(
420 &mut self,
421 env: &Env,
422 ) -> Result<()> {
423 self.handle.with_read_aborted(|aborted| {
424 if !aborted && self.handle.referred.load(Ordering::Relaxed) {
425 check_status!(unsafe {
426 libnode_sys::napi_unref_threadsafe_function(env.0, self.handle.get_raw())
427 })?;
428 self.handle.referred.store(false, Ordering::Relaxed);
429 }
430 Ok(())
431 })
432 }
433
434 pub fn aborted(&self) -> bool {
435 self.handle.with_read_aborted(|aborted| aborted)
436 }
437
438 pub fn abort(self) -> Result<()> {
439 self.handle.with_write_aborted(|mut aborted_guard| {
440 if !*aborted_guard {
441 check_status!(unsafe {
442 libnode_sys::napi_release_threadsafe_function(
443 self.handle.get_raw(),
444 libnode_sys::ThreadsafeFunctionReleaseMode::abort,
445 )
446 })?;
447 *aborted_guard = true;
448 }
449 Ok(())
450 })
451 }
452
453 pub fn raw(&self) -> libnode_sys::napi_threadsafe_function {
455 self.handle.get_raw()
456 }
457}
458
459impl<T: 'static> ThreadsafeFunction<T, ErrorStrategy::CalleeHandled> {
460 pub fn call(
463 &self,
464 value: Result<T>,
465 mode: ThreadsafeFunctionCallMode,
466 ) -> Status {
467 self.handle.with_read_aborted(|aborted| {
468 if aborted {
469 return Status::Closing;
470 }
471
472 unsafe {
473 libnode_sys::napi_call_threadsafe_function(
474 self.handle.get_raw(),
475 Box::into_raw(Box::new(value.map(|data| {
476 ThreadsafeFunctionCallJsBackData {
477 data,
478 call_variant: ThreadsafeFunctionCallVariant::Direct,
479 callback: Box::new(|_d: Result<JsUnknown>| Ok(())),
480 }
481 })))
482 .cast(),
483 mode.into(),
484 )
485 }
486 .into()
487 })
488 }
489
490 pub fn call_with_return_value<D: FromNapiValue, F: 'static + FnOnce(D) -> Result<()>>(
491 &self,
492 value: Result<T>,
493 mode: ThreadsafeFunctionCallMode,
494 cb: F,
495 ) -> Status {
496 self.handle.with_read_aborted(|aborted| {
497 if aborted {
498 return Status::Closing;
499 }
500
501 unsafe {
502 libnode_sys::napi_call_threadsafe_function(
503 self.handle.get_raw(),
504 Box::into_raw(Box::new(value.map(|data| {
505 ThreadsafeFunctionCallJsBackData {
506 data,
507 call_variant: ThreadsafeFunctionCallVariant::WithCallback,
508 callback: Box::new(move |d: Result<JsUnknown>| {
509 d.and_then(|d| D::from_napi_value(d.0.env, d.0.value).and_then(cb))
510 }),
511 }
512 })))
513 .cast(),
514 mode.into(),
515 )
516 }
517 .into()
518 })
519 }
520}
521
522impl<T: 'static> ThreadsafeFunction<T, ErrorStrategy::Fatal> {
523 pub fn call(
526 &self,
527 value: T,
528 mode: ThreadsafeFunctionCallMode,
529 ) -> Status {
530 self.handle.with_read_aborted(|aborted| {
531 if aborted {
532 return Status::Closing;
533 }
534
535 unsafe {
536 libnode_sys::napi_call_threadsafe_function(
537 self.handle.get_raw(),
538 Box::into_raw(Box::new(ThreadsafeFunctionCallJsBackData {
539 data: value,
540 call_variant: ThreadsafeFunctionCallVariant::Direct,
541 callback: Box::new(|_d: Result<JsUnknown>| Ok(())),
542 }))
543 .cast(),
544 mode.into(),
545 )
546 }
547 .into()
548 })
549 }
550
551 pub fn call_with_return_value<D: FromNapiValue, F: 'static + FnOnce(D) -> Result<()>>(
552 &self,
553 value: T,
554 mode: ThreadsafeFunctionCallMode,
555 cb: F,
556 ) -> Status {
557 self.handle.with_read_aborted(|aborted| {
558 if aborted {
559 return Status::Closing;
560 }
561
562 unsafe {
563 libnode_sys::napi_call_threadsafe_function(
564 self.handle.get_raw(),
565 Box::into_raw(Box::new(ThreadsafeFunctionCallJsBackData {
566 data: value,
567 call_variant: ThreadsafeFunctionCallVariant::WithCallback,
568 callback: Box::new(move |d: Result<JsUnknown>| {
569 d.and_then(|d| D::from_napi_value(d.0.env, d.0.value).and_then(cb))
570 }),
571 }))
572 .cast(),
573 mode.into(),
574 )
575 }
576 .into()
577 })
578 }
579}
580
581#[allow(unused_variables)]
582unsafe extern "C" fn thread_finalize_cb<T: 'static, V: ToNapiValue, R>(
583 env: libnode_sys::napi_env,
584 finalize_data: *mut c_void,
585 finalize_hint: *mut c_void,
586) where
587 R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
588{
589 let handle_option =
590 unsafe { Weak::from_raw(finalize_data.cast::<ThreadsafeFunctionHandle>()).upgrade() };
591
592 if let Some(handle) = handle_option {
593 handle.with_write_aborted(|mut aborted_guard| {
594 if !*aborted_guard {
595 *aborted_guard = true;
596 }
597 });
598 }
599
600 drop(unsafe { Box::<R>::from_raw(finalize_hint.cast()) });
602}
603
604unsafe extern "C" fn call_js_cb<T: 'static, V: ToNapiValue, R, ES>(
605 raw_env: libnode_sys::napi_env,
606 js_callback: libnode_sys::napi_value,
607 context: *mut c_void,
608 data: *mut c_void,
609) where
610 R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
611 ES: ErrorStrategy::T,
612{
613 if raw_env.is_null() || js_callback.is_null() {
615 return;
616 }
617
618 let ctx: &mut R = unsafe { Box::leak(Box::from_raw(context.cast())) };
619 let val = unsafe {
620 match ES::VALUE {
621 ErrorStrategy::CalleeHandled::VALUE => {
622 *Box::<Result<ThreadsafeFunctionCallJsBackData<T>>>::from_raw(data.cast())
623 }
624 ErrorStrategy::Fatal::VALUE => Ok(*Box::<ThreadsafeFunctionCallJsBackData<T>>::from_raw(
625 data.cast(),
626 )),
627 }
628 };
629
630 let mut recv = ptr::null_mut();
631 unsafe { libnode_sys::napi_get_undefined(raw_env, &mut recv) };
632
633 let ret = val.and_then(|v| {
634 (ctx)(ThreadSafeCallContext {
635 env: unsafe { Env::from_raw(raw_env) },
636 value: v.data,
637 })
638 .map(|ret| (ret, v.call_variant, v.callback))
639 });
640
641 let status = match ret {
645 Ok((values, call_variant, callback)) => {
646 let values = values
647 .into_iter()
648 .map(|v| unsafe { ToNapiValue::to_napi_value(raw_env, v) });
649 let args: Result<Vec<libnode_sys::napi_value>> =
650 if ES::VALUE == ErrorStrategy::CalleeHandled::VALUE {
651 let mut js_null = ptr::null_mut();
652 unsafe { libnode_sys::napi_get_null(raw_env, &mut js_null) };
653 ::core::iter::once(Ok(js_null)).chain(values).collect()
654 } else {
655 values.collect()
656 };
657 let mut return_value = ptr::null_mut();
658 let mut status = match args {
659 Ok(args) => unsafe {
660 libnode_sys::napi_call_function(
661 raw_env,
662 recv,
663 js_callback,
664 args.len(),
665 args.as_ptr(),
666 &mut return_value,
667 )
668 },
669 Err(e) => match ES::VALUE {
670 ErrorStrategy::Fatal::VALUE => unsafe {
671 libnode_sys::napi_fatal_exception(raw_env, JsError::from(e).into_value(raw_env))
672 },
673 ErrorStrategy::CalleeHandled::VALUE => unsafe {
674 libnode_sys::napi_call_function(
675 raw_env,
676 recv,
677 js_callback,
678 1,
679 [JsError::from(e).into_value(raw_env)].as_mut_ptr(),
680 &mut return_value,
681 )
682 },
683 },
684 };
685 if let ThreadsafeFunctionCallVariant::WithCallback = call_variant {
686 let callback_arg = if status == libnode_sys::Status::napi_pending_exception {
688 let mut exception = ptr::null_mut();
689 status =
690 unsafe { libnode_sys::napi_get_and_clear_last_exception(raw_env, &mut exception) };
691 Err(
692 JsUnknown(crate::napi::Value {
693 env: raw_env,
694 value: exception,
695 value_type: crate::napi::ValueType::Unknown,
696 })
697 .into(),
698 )
699 } else {
700 Ok(JsUnknown(crate::napi::Value {
701 env: raw_env,
702 value: return_value,
703 value_type: crate::napi::ValueType::Unknown,
704 }))
705 };
706 if let Err(err) = callback(callback_arg) {
707 let message = format!(
708 "Failed to convert return value in ThreadsafeFunction callback into Rust value: {err}"
709 );
710 let message_length = message.len();
711 let c_message = CString::new(message).unwrap();
712 unsafe {
713 libnode_sys::napi_fatal_error(
714 "threadsafe_function.rs:749\0".as_ptr().cast(),
715 26,
716 c_message.as_ptr(),
717 message_length as isize,
718 )
719 };
720 }
721 }
722 status
723 }
724 Err(e) if ES::VALUE == ErrorStrategy::Fatal::VALUE => unsafe {
725 libnode_sys::napi_fatal_exception(raw_env, JsError::from(e).into_value(raw_env))
726 },
727 Err(e) => unsafe {
728 libnode_sys::napi_call_function(
729 raw_env,
730 recv,
731 js_callback,
732 1,
733 [JsError::from(e).into_value(raw_env)].as_mut_ptr(),
734 ptr::null_mut(),
735 )
736 },
737 };
738 handle_call_js_cb_status(status, raw_env)
739}
740
741fn handle_call_js_cb_status(
742 status: libnode_sys::napi_status,
743 raw_env: libnode_sys::napi_env,
744) {
745 if status == libnode_sys::Status::napi_ok {
746 return;
747 }
748 if status == libnode_sys::Status::napi_pending_exception {
749 let mut error_result = ptr::null_mut();
750 assert_eq!(
751 unsafe { libnode_sys::napi_get_and_clear_last_exception(raw_env, &mut error_result) },
752 libnode_sys::Status::napi_ok
753 );
754
755 let stat = unsafe { libnode_sys::napi_fatal_exception(raw_env, error_result) };
757 assert!(
758 stat == libnode_sys::Status::napi_ok || stat == libnode_sys::Status::napi_pending_exception
759 );
760 } else {
761 let error_code: Status = status.into();
762 let error_code_string = format!("{error_code:?}");
763 let mut error_code_value = ptr::null_mut();
764 assert_eq!(
765 unsafe {
766 libnode_sys::napi_create_string_utf8(
767 raw_env,
768 error_code_string.as_ptr() as *const _,
769 error_code_string.len() as isize,
770 &mut error_code_value,
771 )
772 },
773 libnode_sys::Status::napi_ok,
774 );
775 let error_msg = "Call JavaScript callback failed in threadsafe function";
776 let mut error_msg_value = ptr::null_mut();
777 assert_eq!(
778 unsafe {
779 libnode_sys::napi_create_string_utf8(
780 raw_env,
781 error_msg.as_ptr() as *const _,
782 error_msg.len() as isize,
783 &mut error_msg_value,
784 )
785 },
786 libnode_sys::Status::napi_ok,
787 );
788 let mut error_value = ptr::null_mut();
789 assert_eq!(
790 unsafe {
791 libnode_sys::napi_create_error(raw_env, error_code_value, error_msg_value, &mut error_value)
792 },
793 libnode_sys::Status::napi_ok,
794 );
795 assert_eq!(
796 unsafe { libnode_sys::napi_fatal_exception(raw_env, error_value) },
797 libnode_sys::Status::napi_ok
798 );
799 }
800}
801
802macro_rules! type_level_enum {(
804 $( #[doc = $doc:tt] )*
805 $pub:vis
806 enum $EnumName:ident {
807 $(
808 $( #[doc = $doc_variant:tt] )*
809 $Variant:ident
810 ),* $(,)?
811 }
812) => (type_level_enum! { with_docs! {
814 $( #[doc = $doc] )*
815 #[doc = ::core::concat!(
826 " enum ", ::core::stringify!($EnumName), " {",
827 )]
828 $(
829 #[doc = ::core::concat!(
830 " ", ::core::stringify!($Variant), ",",
831 )]
832 )*
833 #[doc = " }"]
834 #[doc = ::core::concat!(
837 "With [`", ::core::stringify!($EnumName), "::T`](#reexports) \
838 being the type-level \"enum type\":",
839 )]
840 #[doc = ::core::concat!(
843 "<Param: ", ::core::stringify!($EnumName), "::T>"
844 )]
845 }
847 #[allow(warnings)]
848 $pub mod $EnumName {
849 #[doc(no_inline)]
850 pub use $EnumName as T;
851
852 super::type_level_enum! {
853 with_docs! {
854 #[doc = ::core::concat!(
855 "See [`", ::core::stringify!($EnumName), "`]\
856 [super::", ::core::stringify!($EnumName), "]"
857 )]
858 }
859 pub trait $EnumName : __sealed::$EnumName + ::core::marker::Sized + 'static {
860 const VALUE: __value::$EnumName;
861 }
862 }
863
864 mod __sealed { pub trait $EnumName {} }
865
866 mod __value {
867 #[derive(Debug, PartialEq, Eq)]
868 pub enum $EnumName { $( $Variant ),* }
869 }
870
871 $(
872 $( #[doc = $doc_variant] )*
873 pub enum $Variant {}
874 impl __sealed::$EnumName for $Variant {}
875 impl $EnumName for $Variant {
876 const VALUE: __value::$EnumName = __value::$EnumName::$Variant;
877 }
878 impl $Variant {
879 pub const VALUE: __value::$EnumName = __value::$EnumName::$Variant;
880 }
881 )*
882 }
883});(
884 with_docs! {
885 $( #[doc = $doc:expr] )*
886 }
887 $item:item
888) => (
889 $( #[doc = $doc] )*
890 $item
891)}
892
893use type_level_enum;
894
895pub struct UnknownReturnValue;
896
897impl TypeName for UnknownReturnValue {
898 fn type_name() -> &'static str {
899 "UnknownReturnValue"
900 }
901
902 fn value_type() -> crate::napi::ValueType {
903 crate::napi::ValueType::Unknown
904 }
905}
906
907impl ValidateNapiValue for UnknownReturnValue {}
908
909impl FromNapiValue for UnknownReturnValue {
910 unsafe fn from_napi_value(
911 _env: libnode_sys::napi_env,
912 _napi_val: libnode_sys::napi_value,
913 ) -> Result<Self> {
914 Ok(UnknownReturnValue)
915 }
916}