neon/types_impl/
private.rs1use std::{ffi::c_void, mem::MaybeUninit};
2
3use crate::{
4 context::{
5 internal::{ContextInternal, Env},
6 Context, Cx,
7 },
8 handle::{internal::TransparentNoCopyWrapper, Handle},
9 result::{JsResult, NeonResult, Throw},
10 sys::{self, bindings as napi, raw},
11 types::Value,
12};
13
14use super::JsValue;
15
16const V8_ARGC_LIMIT: usize = 65535;
18
19pub(crate) unsafe fn prepare_call<'a, 'b, C: Context<'a>>(
20 cx: &mut C,
21 args: &[Handle<'b, JsValue>],
22) -> NeonResult<(usize, *const c_void)> {
23 let argv = args.as_ptr().cast();
27 let argc = args.len();
28 if argc > V8_ARGC_LIMIT {
29 return cx.throw_range_error("too many arguments");
30 }
31 Ok((argc, argv))
32}
33
34pub trait ValueInternal: TransparentNoCopyWrapper + 'static {
35 fn name() -> &'static str;
36
37 fn is_typeof<Other: Value>(cx: &mut Cx, other: &Other) -> bool;
38
39 fn downcast<Other: Value>(cx: &mut Cx, other: &Other) -> Option<Self> {
40 if Self::is_typeof(cx, other) {
41 Some(unsafe { Self::from_local(cx.env(), other.to_local()) })
44 } else {
45 None
46 }
47 }
48
49 fn cast<'a, T: Value, F: FnOnce(raw::Local) -> T>(self, f: F) -> Handle<'a, T> {
50 Handle::new_internal(f(self.to_local()))
51 }
52
53 fn to_local(&self) -> raw::Local;
54
55 unsafe fn from_local(env: Env, h: raw::Local) -> Self;
58
59 unsafe fn try_call<'a, 'b, C: Context<'a>, T, AS>(
60 &self,
61 cx: &mut C,
62 this: Handle<'b, T>,
63 args: AS,
64 ) -> JsResult<'a, JsValue>
65 where
66 T: Value,
67 AS: AsRef<[Handle<'b, JsValue>]>,
68 {
69 let callee = self.to_local();
70 let (argc, argv) = unsafe { prepare_call(cx, args.as_ref()) }?;
71 let env = cx.env();
72 let mut result: MaybeUninit<raw::Local> = MaybeUninit::zeroed();
73
74 let status = napi::call_function(
75 env.to_raw(),
76 this.to_local(),
77 callee,
78 argc,
79 argv.cast(),
80 result.as_mut_ptr(),
81 );
82
83 check_call_status(cx, callee, status)?;
84
85 Ok(Handle::new_internal(JsValue::from_local(
86 env,
87 result.assume_init(),
88 )))
89 }
90
91 unsafe fn try_construct<'a, 'b, C: Context<'a>, AS>(
92 &self,
93 cx: &mut C,
94 args: AS,
95 ) -> JsResult<'a, JsValue>
96 where
97 AS: AsRef<[Handle<'b, JsValue>]>,
98 {
99 let callee = self.to_local();
100 let (argc, argv) = unsafe { prepare_call(cx, args.as_ref()) }?;
101 let env = cx.env();
102 let mut result: MaybeUninit<raw::Local> = MaybeUninit::zeroed();
103 let status =
104 napi::new_instance(env.to_raw(), callee, argc, argv.cast(), result.as_mut_ptr());
105
106 check_call_status(cx, callee, status)?;
107
108 Ok(Handle::new_internal(JsValue::from_local(
109 env,
110 result.assume_init(),
111 )))
112 }
113}
114
115unsafe fn check_call_status<'a, C: Context<'a>>(
116 cx: &mut C,
117 callee: raw::Local,
118 status: Result<(), sys::Status>,
119) -> NeonResult<()> {
120 match status {
121 Err(sys::Status::InvalidArg) if !sys::tag::is_function(cx.env().to_raw(), callee) => {
122 return cx.throw_error("not a function");
123 }
124 Err(sys::Status::PendingException) => {
125 return Err(Throw::new());
126 }
127 status => status.unwrap(),
128 }
129
130 Ok(())
131}