ic_wasm_bindgen/convert/
impls.rs1use core::char;
2use core::mem::{self, ManuallyDrop};
3
4use crate::convert::traits::{WasmAbi, WasmPrimitive};
5use crate::convert::{FromWasmAbi, IntoWasmAbi, LongRefFromWasmAbi, RefFromWasmAbi};
6use crate::convert::{OptionFromWasmAbi, OptionIntoWasmAbi, ReturnWasmAbi};
7use crate::{Clamped, JsError, JsValue, UnwrapThrowExt};
8
9if_std! {
10 use std::boxed::Box;
11 use std::convert::{TryFrom, TryInto};
12 use std::fmt::Debug;
13 use std::vec::Vec;
14}
15
16impl<T: WasmPrimitive> WasmAbi for T {
18 type Prim1 = Self;
19 type Prim2 = ();
20 type Prim3 = ();
21 type Prim4 = ();
22
23 #[inline]
24 fn split(self) -> (Self, (), (), ()) {
25 (self, (), (), ())
26 }
27
28 #[inline]
29 fn join(prim: Self, _: (), _: (), _: ()) -> Self {
30 prim
31 }
32}
33
34impl<T: WasmAbi<Prim4 = ()>> WasmAbi for Option<T> {
35 type Prim1 = u32;
37 type Prim2 = T::Prim1;
38 type Prim3 = T::Prim2;
39 type Prim4 = T::Prim3;
40
41 #[inline]
42 fn split(self) -> (u32, T::Prim1, T::Prim2, T::Prim3) {
43 match self {
44 None => (
45 0,
46 Default::default(),
47 Default::default(),
48 Default::default(),
49 ),
50 Some(value) => {
51 let (prim1, prim2, prim3, ()) = value.split();
52 (1, prim1, prim2, prim3)
53 }
54 }
55 }
56
57 #[inline]
58 fn join(is_some: u32, prim1: T::Prim1, prim2: T::Prim2, prim3: T::Prim3) -> Self {
59 if is_some == 0 {
60 None
61 } else {
62 Some(T::join(prim1, prim2, prim3, ()))
63 }
64 }
65}
66
67macro_rules! type_wasm_native {
68 ($($t:tt as $c:tt)*) => ($(
69 impl IntoWasmAbi for $t {
70 type Abi = $c;
71
72 #[inline]
73 fn into_abi(self) -> $c { self as $c }
74 }
75
76 impl FromWasmAbi for $t {
77 type Abi = $c;
78
79 #[inline]
80 unsafe fn from_abi(js: $c) -> Self { js as $t }
81 }
82
83 impl IntoWasmAbi for Option<$t> {
84 type Abi = Option<$c>;
85
86 #[inline]
87 fn into_abi(self) -> Self::Abi {
88 self.map(|v| v as $c)
89 }
90 }
91
92 impl FromWasmAbi for Option<$t> {
93 type Abi = Option<$c>;
94
95 #[inline]
96 unsafe fn from_abi(js: Self::Abi) -> Self {
97 js.map(|v: $c| v as $t)
98 }
99 }
100 )*)
101}
102
103type_wasm_native!(
104 i32 as i32
105 isize as i32
106 u32 as u32
107 usize as u32
108 i64 as i64
109 u64 as u64
110 f32 as f32
111 f64 as f64
112);
113
114macro_rules! type_abi_as_u32 {
115 ($($t:tt)*) => ($(
116 impl IntoWasmAbi for $t {
117 type Abi = u32;
118
119 #[inline]
120 fn into_abi(self) -> u32 { self as u32 }
121 }
122
123 impl FromWasmAbi for $t {
124 type Abi = u32;
125
126 #[inline]
127 unsafe fn from_abi(js: u32) -> Self { js as $t }
128 }
129
130 impl OptionIntoWasmAbi for $t {
131 #[inline]
132 fn none() -> u32 { 0x00FF_FFFFu32 }
133 }
134
135 impl OptionFromWasmAbi for $t {
136 #[inline]
137 fn is_none(js: &u32) -> bool { *js == 0x00FF_FFFFu32 }
138 }
139 )*)
140}
141
142type_abi_as_u32!(i8 u8 i16 u16);
143
144impl IntoWasmAbi for bool {
145 type Abi = u32;
146
147 #[inline]
148 fn into_abi(self) -> u32 {
149 self as u32
150 }
151}
152
153impl FromWasmAbi for bool {
154 type Abi = u32;
155
156 #[inline]
157 unsafe fn from_abi(js: u32) -> bool {
158 js != 0
159 }
160}
161
162impl OptionIntoWasmAbi for bool {
163 #[inline]
164 fn none() -> u32 {
165 0x00FF_FFFFu32
166 }
167}
168
169impl OptionFromWasmAbi for bool {
170 #[inline]
171 fn is_none(js: &u32) -> bool {
172 *js == 0x00FF_FFFFu32
173 }
174}
175
176impl IntoWasmAbi for char {
177 type Abi = u32;
178
179 #[inline]
180 fn into_abi(self) -> u32 {
181 self as u32
182 }
183}
184
185impl FromWasmAbi for char {
186 type Abi = u32;
187
188 #[inline]
189 unsafe fn from_abi(js: u32) -> char {
190 char::from_u32_unchecked(js)
191 }
192}
193
194impl OptionIntoWasmAbi for char {
195 #[inline]
196 fn none() -> u32 {
197 0x00FF_FFFFu32
198 }
199}
200
201impl OptionFromWasmAbi for char {
202 #[inline]
203 fn is_none(js: &u32) -> bool {
204 *js == 0x00FF_FFFFu32
205 }
206}
207
208impl<T> IntoWasmAbi for *const T {
209 type Abi = u32;
210
211 #[inline]
212 fn into_abi(self) -> u32 {
213 self as u32
214 }
215}
216
217impl<T> FromWasmAbi for *const T {
218 type Abi = u32;
219
220 #[inline]
221 unsafe fn from_abi(js: u32) -> *const T {
222 js as *const T
223 }
224}
225
226impl<T> IntoWasmAbi for *mut T {
227 type Abi = u32;
228
229 #[inline]
230 fn into_abi(self) -> u32 {
231 self as u32
232 }
233}
234
235impl<T> FromWasmAbi for *mut T {
236 type Abi = u32;
237
238 #[inline]
239 unsafe fn from_abi(js: u32) -> *mut T {
240 js as *mut T
241 }
242}
243
244impl IntoWasmAbi for JsValue {
245 type Abi = u32;
246
247 #[inline]
248 fn into_abi(self) -> u32 {
249 let ret = self.idx;
250 mem::forget(self);
251 ret
252 }
253}
254
255impl FromWasmAbi for JsValue {
256 type Abi = u32;
257
258 #[inline]
259 unsafe fn from_abi(js: u32) -> JsValue {
260 JsValue::_new(js)
261 }
262}
263
264impl<'a> IntoWasmAbi for &'a JsValue {
265 type Abi = u32;
266
267 #[inline]
268 fn into_abi(self) -> u32 {
269 self.idx
270 }
271}
272
273impl RefFromWasmAbi for JsValue {
274 type Abi = u32;
275 type Anchor = ManuallyDrop<JsValue>;
276
277 #[inline]
278 unsafe fn ref_from_abi(js: u32) -> Self::Anchor {
279 ManuallyDrop::new(JsValue::_new(js))
280 }
281}
282
283impl LongRefFromWasmAbi for JsValue {
284 type Abi = u32;
285 type Anchor = JsValue;
286
287 #[inline]
288 unsafe fn long_ref_from_abi(js: u32) -> Self::Anchor {
289 Self::from_abi(js)
290 }
291}
292
293impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> {
294 type Abi = T::Abi;
295
296 #[inline]
297 fn into_abi(self) -> T::Abi {
298 match self {
299 None => T::none(),
300 Some(me) => me.into_abi(),
301 }
302 }
303}
304
305impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
306 type Abi = T::Abi;
307
308 #[inline]
309 unsafe fn from_abi(js: T::Abi) -> Self {
310 if T::is_none(&js) {
311 None
312 } else {
313 Some(T::from_abi(js))
314 }
315 }
316}
317
318impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
319 type Abi = T::Abi;
320
321 #[inline]
322 fn into_abi(self) -> Self::Abi {
323 self.0.into_abi()
324 }
325}
326
327impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
328 type Abi = T::Abi;
329
330 #[inline]
331 unsafe fn from_abi(js: T::Abi) -> Self {
332 Clamped(T::from_abi(js))
333 }
334}
335
336impl IntoWasmAbi for () {
337 type Abi = ();
338
339 #[inline]
340 fn into_abi(self) {
341 self
342 }
343}
344
345impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> {
346 type Prim1 = T::Prim1;
347 type Prim2 = T::Prim2;
348 type Prim3 = u32;
353 type Prim4 = u32;
355
356 #[inline]
357 fn split(self) -> (T::Prim1, T::Prim2, u32, u32) {
358 match self {
359 Ok(value) => {
360 let (prim1, prim2, (), ()) = value.split();
361 (prim1, prim2, 0, 0)
362 }
363 Err(err) => (Default::default(), Default::default(), err, 1),
364 }
365 }
366
367 #[inline]
368 fn join(prim1: T::Prim1, prim2: T::Prim2, err: u32, is_err: u32) -> Self {
369 if is_err == 0 {
370 Ok(T::join(prim1, prim2, (), ()))
371 } else {
372 Err(err)
373 }
374 }
375}
376
377impl<T, E> ReturnWasmAbi for Result<T, E>
378where
379 T: IntoWasmAbi,
380 E: Into<JsValue>,
381 T::Abi: WasmAbi<Prim3 = (), Prim4 = ()>,
382{
383 type Abi = Result<T::Abi, u32>;
384
385 #[inline]
386 fn return_abi(self) -> Self::Abi {
387 match self {
388 Ok(v) => Ok(v.into_abi()),
389 Err(e) => {
390 let jsval = e.into();
391 Err(jsval.into_abi())
392 }
393 }
394 }
395}
396
397impl IntoWasmAbi for JsError {
398 type Abi = <JsValue as IntoWasmAbi>::Abi;
399
400 fn into_abi(self) -> Self::Abi {
401 self.value.into_abi()
402 }
403}
404
405if_std! {
406 pub fn js_value_vector_into_abi<T: Into<JsValue>>(vector: Box<[T]>) -> <Box<[JsValue]> as IntoWasmAbi>::Abi {
409 let js_vals: Box<[JsValue]> = vector
410 .into_vec()
411 .into_iter()
412 .map(|x| x.into())
413 .collect();
414
415 js_vals.into_abi()
416 }
417
418 pub unsafe fn js_value_vector_from_abi<T: TryFrom<JsValue>>(js: <Box<[JsValue]> as FromWasmAbi>::Abi) -> Box<[T]> where T::Error: Debug {
419 let js_vals = <Vec<JsValue> as FromWasmAbi>::from_abi(js);
420
421 let mut result = Vec::with_capacity(js_vals.len());
422 for value in js_vals {
423 result.push(value.try_into().expect_throw("array contains a value of the wrong type"));
434 }
435 result.into_boxed_slice()
436 }
437}