wry_bindgen/
try_from_js.rs1use alloc::string::{String, ToString};
4use alloc::vec::Vec;
5
6use crate::{JsCast, JsValue, convert};
7
8macro_rules! cast {
9 (($from:ty => $to:ty) $val:expr) => {{ $crate::__rt::wbg_cast::<$from, $to>($val) }};
10}
11
12macro_rules! to_js_value {
13 ($ty:ty) => {
14 impl From<$ty> for $crate::JsValue {
15 fn from(val: $ty) -> Self {
16 cast! {($ty => $crate::JsValue) val}
17 }
18 }
19 };
20}
21
22macro_rules! from_js_value {
23 ($ty:ty) => {
24 impl From<$crate::JsValue> for $ty {
25 fn from(val: $crate::JsValue) -> Self {
26 cast! {($crate::JsValue => $ty) val}
27 }
28 }
29 };
30}
31
32impl TryFrom<JsValue> for u64 {
33 type Error = JsValue;
34
35 fn try_from(v: JsValue) -> Result<Self, JsValue> {
36 <Self as convert::TryFromJsValue>::try_from_js_value(v)
37 }
38}
39
40impl TryFrom<JsValue> for i64 {
41 type Error = JsValue;
42
43 fn try_from(v: JsValue) -> Result<Self, JsValue> {
44 <Self as convert::TryFromJsValue>::try_from_js_value(v)
45 }
46}
47
48impl TryFrom<JsValue> for f64 {
49 type Error = JsValue;
50
51 fn try_from(val: JsValue) -> Result<Self, Self::Error> {
52 f64::try_from(&val)
53 }
54}
55
56impl TryFrom<&JsValue> for f64 {
57 type Error = JsValue;
58
59 fn try_from(val: &JsValue) -> Result<Self, Self::Error> {
62 let jsval = crate::js_helpers::js_try_into_number(val);
63 jsval.as_f64().ok_or(jsval)
64 }
65}
66
67impl TryFrom<JsValue> for i128 {
68 type Error = JsValue;
69
70 fn try_from(v: JsValue) -> Result<Self, JsValue> {
71 <Self as convert::TryFromJsValue>::try_from_js_value(v)
72 }
73}
74
75impl TryFrom<JsValue> for u128 {
76 type Error = JsValue;
77
78 fn try_from(v: JsValue) -> Result<Self, JsValue> {
79 <Self as convert::TryFromJsValue>::try_from_js_value(v)
80 }
81}
82
83impl TryFrom<JsValue> for String {
84 type Error = JsValue;
85
86 fn try_from(value: JsValue) -> Result<Self, Self::Error> {
87 value.as_string().ok_or(value)
88 }
89}
90
91impl convert::TryFromJsValue for String {
92 fn try_from_js_value_ref(value: &JsValue) -> Option<Self> {
93 value.as_string()
94 }
95}
96
97impl convert::TryFromJsValue for bool {
98 fn try_from_js_value_ref(value: &JsValue) -> Option<Self> {
99 value.as_bool()
100 }
101}
102
103impl convert::TryFromJsValue for char {
104 fn try_from_js_value_ref(value: &JsValue) -> Option<Self> {
105 let s = value.as_string()?;
106 let mut chars = s.chars();
107 let c = chars.next()?;
108 if chars.next().is_none() {
109 Some(c)
110 } else {
111 None
112 }
113 }
114}
115
116impl convert::TryFromJsValue for () {
117 fn try_from_js_value_ref(value: &JsValue) -> Option<Self> {
118 if value.is_undefined() { Some(()) } else { None }
119 }
120}
121
122impl<T: convert::TryFromJsValue> convert::TryFromJsValue for Option<T> {
123 fn try_from_js_value_ref(value: &JsValue) -> Option<Self> {
124 if value.is_undefined() {
125 Some(None)
126 } else {
127 T::try_from_js_value_ref(value).map(Some)
128 }
129 }
130}
131
132impl<T: convert::TryFromJsValue> convert::TryFromJsValue for Vec<T> {
133 fn try_from_js_value_ref(value: &JsValue) -> Option<Self> {
134 if !value.is_array() {
135 return None;
136 }
137 let length = crate::js_helpers::js_reflect_get(value, &JsValue::from_str("length"));
138 let len = length.as_f64()? as u32;
139 let mut out = Vec::with_capacity(len as usize);
140 for i in 0..len {
141 let element = crate::js_helpers::js_reflect_get(value, &JsValue::from_f64(i as f64));
142 out.push(T::try_from_js_value(element).ok()?);
143 }
144 Some(out)
145 }
146}
147
148fn to_uint_32(v: &JsValue) -> Option<u32> {
154 v.as_f64().map(|n| {
155 if n.is_infinite() {
156 0
157 } else {
158 (n as i64) as u32
159 }
160 })
161}
162
163macro_rules! try_from_js_value_int {
164 ($($ty:ty),* $(,)?) => {
165 $(
166 impl convert::TryFromJsValue for $ty {
167 fn try_from_js_value_ref(val: &JsValue) -> Option<$ty> {
168 to_uint_32(val).map(|n| n as $ty)
169 }
170 }
171 )*
172 };
173}
174
175try_from_js_value_int!(i8, u8, i16, u16, i32, u32);
176
177impl convert::TryFromJsValue for f32 {
178 fn try_from_js_value_ref(val: &JsValue) -> Option<f32> {
179 val.as_f64().map(|n| n as f32)
180 }
181}
182
183impl convert::TryFromJsValue for f64 {
184 fn try_from_js_value_ref(val: &JsValue) -> Option<f64> {
185 val.as_f64()
186 }
187}
188
189impl convert::TryFromJsValue for i64 {
190 fn try_from_js_value_ref(val: &JsValue) -> Option<i64> {
191 let as_self = crate::js_helpers::js_bigint_get_as_i64(val)?;
194 if val == &as_self { Some(as_self) } else { None }
195 }
196}
197
198impl convert::TryFromJsValue for u64 {
199 fn try_from_js_value_ref(val: &JsValue) -> Option<u64> {
200 let as_self = crate::js_helpers::js_bigint_get_as_i64(val)?.cast_unsigned();
203 if val == &as_self { Some(as_self) } else { None }
204 }
205}
206
207macro_rules! num128_from_js {
208 ($($ty:ty, $hi_ty:ty;)*) => ($(
209 impl convert::TryFromJsValue for $ty {
210 fn try_from_js_value_ref(v: &JsValue) -> Option<$ty> {
211 let lo = crate::js_helpers::js_bigint_get_as_i64(v)?.cast_unsigned();
213 let hi = v >> JsValue::from(64_u64);
215 <$hi_ty as convert::TryFromJsValue>::try_from_js_value_ref(&hi)
218 .map(|hi| (<$ty>::from(hi) << 64) | <$ty>::from(lo))
219 }
220 }
221 )*)
222}
223
224num128_from_js! {
225 i128, i64;
226 u128, u64;
227}
228
229impl convert::TryFromJsValue for isize {
230 fn try_from_js_value_ref(val: &JsValue) -> Option<isize> {
231 val.as_f64().map(|n| n as isize)
232 }
233}
234
235impl convert::TryFromJsValue for usize {
236 fn try_from_js_value_ref(val: &JsValue) -> Option<usize> {
237 val.as_f64().map(|n| n as usize)
238 }
239}
240
241to_js_value!(i8);
242from_js_value!(i8);
243to_js_value!(i16);
244from_js_value!(i16);
245to_js_value!(i32);
246from_js_value!(i32);
247to_js_value!(i64);
248to_js_value!(i128);
249to_js_value!(u8);
250from_js_value!(u8);
251to_js_value!(u16);
252from_js_value!(u16);
253to_js_value!(u32);
254from_js_value!(u32);
255to_js_value!(u64);
256to_js_value!(u128);
257to_js_value!(f32);
258from_js_value!(f32);
259to_js_value!(f64);
260to_js_value!(usize);
261from_js_value!(usize);
262to_js_value!(isize);
263from_js_value!(isize);
264impl<'a> From<&'a str> for JsValue {
265 fn from(s: &'a str) -> JsValue {
266 cast! {(String => JsValue) s.to_string()}
267 }
268}
269impl<'a> From<&'a String> for JsValue {
270 fn from(s: &'a String) -> JsValue {
271 cast! {(String => JsValue) s.clone()}
272 }
273}
274impl<'a, T> From<&'a T> for JsValue
275where
276 T: JsCast,
277{
278 fn from(s: &'a T) -> JsValue {
279 s.as_ref().clone()
280 }
281}
282impl From<String> for JsValue {
283 fn from(s: String) -> JsValue {
284 cast! {(String => JsValue) s}
285 }
286}
287to_js_value!(());
288from_js_value!(());
289
290impl<T> From<Option<T>> for JsValue
291where
292 T: Into<JsValue>,
293{
294 fn from(s: Option<T>) -> JsValue {
295 match s {
296 Some(s) => s.into(),
297 None => JsValue::undefined(),
298 }
299 }
300}