1use std::{convert::Infallible, ptr};
7
8use crate::{
9 context::{internal::ContextInternal, Cx},
10 handle::{Handle, Root},
11 object::Object,
12 result::{NeonResult, Throw},
13 sys,
14 types::{
15 extract::{TryFromJs, TypeExpected},
16 private::ValueInternal,
17 JsBoolean, JsNumber, JsString, JsValue, Value,
18 },
19};
20
21#[cfg(feature = "napi-5")]
22use crate::types::{extract::Date, JsDate};
23
24impl<'cx, V> TryFromJs<'cx> for Handle<'cx, V>
25where
26 V: Value,
27{
28 type Error = TypeExpected<V>;
29
30 fn try_from_js(
31 cx: &mut Cx<'cx>,
32 v: Handle<'cx, JsValue>,
33 ) -> NeonResult<Result<Self, Self::Error>> {
34 Ok(v.downcast(cx).map_err(|_| TypeExpected::new()))
35 }
36}
37
38impl<'cx, O> TryFromJs<'cx> for Root<O>
39where
40 O: Object,
41{
42 type Error = TypeExpected<O>;
43
44 fn try_from_js(
45 cx: &mut Cx<'cx>,
46 v: Handle<'cx, JsValue>,
47 ) -> NeonResult<Result<Self, Self::Error>> {
48 Ok(match v.downcast::<O, _>(cx) {
49 Ok(v) => Ok(v.root(cx)),
50 Err(_) => Err(TypeExpected::new()),
51 })
52 }
53}
54
55impl<'cx, T> TryFromJs<'cx> for Option<T>
56where
57 T: TryFromJs<'cx>,
58{
59 type Error = T::Error;
60
61 fn try_from_js(
62 cx: &mut Cx<'cx>,
63 v: Handle<'cx, JsValue>,
64 ) -> NeonResult<Result<Self, Self::Error>> {
65 if is_null_or_undefined(cx, v)? {
66 return Ok(Ok(None));
67 }
68
69 T::try_from_js(cx, v).map(|v| v.map(Some))
70 }
71}
72
73impl<'cx> TryFromJs<'cx> for f64 {
74 type Error = TypeExpected<JsNumber>;
75
76 fn try_from_js(
77 cx: &mut Cx<'cx>,
78 v: Handle<'cx, JsValue>,
79 ) -> NeonResult<Result<Self, Self::Error>> {
80 let mut n = 0f64;
81
82 unsafe {
83 match sys::get_value_double(cx.env().to_raw(), v.to_local(), &mut n) {
84 Err(sys::Status::NumberExpected) => return Ok(Err(TypeExpected::new())),
85 Err(sys::Status::PendingException) => return Err(Throw::new()),
86 status => status.unwrap(),
87 };
88 }
89
90 Ok(Ok(n))
91 }
92}
93
94impl<'cx> TryFromJs<'cx> for u32 {
95 type Error = TypeExpected<JsNumber>;
96
97 fn try_from_js(
98 cx: &mut Cx<'cx>,
99 v: Handle<'cx, JsValue>,
100 ) -> NeonResult<Result<Self, Self::Error>> {
101 let mut n = 0u32;
102
103 unsafe {
104 match sys::get_value_uint32(cx.env().to_raw(), v.to_local(), &mut n) {
105 Err(sys::Status::NumberExpected) => return Ok(Err(TypeExpected::new())),
106 Err(sys::Status::PendingException) => return Err(Throw::new()),
107 status => status.unwrap(),
108 };
109 }
110
111 Ok(Ok(n))
112 }
113}
114
115impl<'cx> TryFromJs<'cx> for i32 {
116 type Error = TypeExpected<JsNumber>;
117
118 fn try_from_js(
119 cx: &mut Cx<'cx>,
120 v: Handle<'cx, JsValue>,
121 ) -> NeonResult<Result<Self, Self::Error>> {
122 let mut n = 0i32;
123
124 unsafe {
125 match sys::get_value_int32(cx.env().to_raw(), v.to_local(), &mut n) {
126 Err(sys::Status::NumberExpected) => return Ok(Err(TypeExpected::new())),
127 Err(sys::Status::PendingException) => return Err(Throw::new()),
128 status => status.unwrap(),
129 };
130 }
131
132 Ok(Ok(n))
133 }
134}
135
136impl<'cx> TryFromJs<'cx> for bool {
137 type Error = TypeExpected<JsBoolean>;
138
139 fn try_from_js(
140 cx: &mut Cx<'cx>,
141 v: Handle<'cx, JsValue>,
142 ) -> NeonResult<Result<Self, Self::Error>> {
143 let mut b = false;
144
145 unsafe {
146 match sys::get_value_bool(cx.env().to_raw(), v.to_local(), &mut b) {
147 Err(sys::Status::BooleanExpected) => return Ok(Err(TypeExpected::new())),
148 Err(sys::Status::PendingException) => return Err(Throw::new()),
149 status => status.unwrap(),
150 };
151 }
152
153 Ok(Ok(b))
154 }
155}
156
157impl<'cx> TryFromJs<'cx> for String {
158 type Error = TypeExpected<JsString>;
159
160 fn try_from_js(
161 cx: &mut Cx<'cx>,
162 v: Handle<'cx, JsValue>,
163 ) -> NeonResult<Result<Self, Self::Error>> {
164 let env = cx.env().to_raw();
165 let v = v.to_local();
166 let mut len = 0usize;
167
168 unsafe {
169 match sys::get_value_string_utf8(env, v, ptr::null_mut(), 0, &mut len) {
170 Err(sys::Status::StringExpected) => return Ok(Err(TypeExpected::new())),
171 Err(sys::Status::PendingException) => return Err(Throw::new()),
172 status => status.unwrap(),
173 };
174 }
175
176 let mut buf = Vec::<u8>::with_capacity(len + 1);
178 let mut written = 0usize;
179
180 unsafe {
181 assert_eq!(
182 sys::get_value_string_utf8(
183 env,
184 v,
185 buf.as_mut_ptr().cast(),
186 buf.capacity(),
187 &mut written,
188 ),
189 Ok(())
190 );
191
192 debug_assert_eq!(len, written);
193 buf.set_len(len);
194
195 Ok(Ok(String::from_utf8_unchecked(buf)))
196 }
197 }
198}
199
200#[cfg_attr(docsrs, doc(cfg(feature = "napi-5")))]
201#[cfg(feature = "napi-5")]
202impl<'cx> TryFromJs<'cx> for Date {
203 type Error = TypeExpected<JsDate>;
204
205 fn try_from_js(
206 cx: &mut Cx<'cx>,
207 v: Handle<'cx, JsValue>,
208 ) -> NeonResult<Result<Self, Self::Error>> {
209 let mut d = 0f64;
210
211 unsafe {
212 match sys::get_date_value(cx.env().to_raw(), v.to_local(), &mut d) {
213 Err(sys::Status::DateExpected) => return Ok(Err(TypeExpected::new())),
214 Err(sys::Status::PendingException) => return Err(Throw::new()),
215 status => status.unwrap(),
216 };
217 }
218
219 Ok(Ok(Date(d)))
220 }
221}
222
223impl<'cx> TryFromJs<'cx> for () {
234 type Error = Infallible;
235
236 fn try_from_js(
237 _cx: &mut Cx<'cx>,
238 _v: Handle<'cx, JsValue>,
239 ) -> NeonResult<Result<Self, Self::Error>> {
240 Ok(Ok(()))
241 }
242}
243
244fn is_null_or_undefined<V>(cx: &mut Cx, v: Handle<V>) -> NeonResult<bool>
245where
246 V: Value,
247{
248 let mut ty = sys::ValueType::Object;
249
250 unsafe {
251 match sys::typeof_value(cx.env().to_raw(), v.to_local(), &mut ty) {
252 Err(sys::Status::PendingException) => return Err(Throw::new()),
253 status => status.unwrap(),
254 };
255 }
256
257 Ok(matches!(
258 ty,
259 sys::ValueType::Undefined | sys::ValueType::Null,
260 ))
261}