1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::mem::{self, MaybeUninit};
5use core::ops::{Deref, DerefMut};
6use core::str;
7
8use crate::__rt::{marker::ErasableGeneric, WasmWord};
9use crate::__wbindgen_copy_to_typed_array;
10use crate::convert::{
11 js_value_vector_from_abi, js_value_vector_into_abi, FromWasmAbi, IntoWasmAbi,
12 LongRefFromWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi, RefFromWasmAbi, RefMutFromWasmAbi,
13 UpcastFrom, VectorFromWasmAbi, VectorIntoWasmAbi, WasmAbi,
14};
15use crate::describe::*;
16use crate::JsValue;
17
18use cfg_if::cfg_if;
19
20#[repr(C)]
29#[derive(Clone, Copy)]
30pub struct WasmSlice {
31 pub ptr: WasmWord,
32 pub len: WasmWord,
33}
34
35impl WasmSlice {
36 #[inline]
37 pub fn from_usize(ptr: usize, len: usize) -> Self {
38 Self {
39 ptr: WasmWord::from_usize(ptr),
40 len: WasmWord::from_usize(len),
41 }
42 }
43}
44
45impl WasmAbi for WasmSlice {
46 type Prim1 = <WasmWord as WasmAbi>::Prim1;
48 type Prim2 = <WasmWord as WasmAbi>::Prim1;
50 type Prim3 = ();
51 type Prim4 = ();
52
53 #[inline]
54 fn split(self) -> (Self::Prim1, Self::Prim2, (), ()) {
55 (self.ptr.split().0, self.len.split().0, (), ())
56 }
57
58 #[inline]
59 fn join(ptr: Self::Prim1, len: Self::Prim2, _: (), _: ()) -> Self {
60 Self {
61 ptr: WasmWord::join(ptr, (), (), ()),
62 len: WasmWord::join(len, (), (), ()),
63 }
64 }
65}
66
67#[inline]
68fn null_slice() -> WasmSlice {
69 WasmSlice::from_usize(0, 0)
70}
71
72pub struct WasmMutSlice {
73 pub slice: WasmSlice,
74 pub idx: u32,
75}
76
77impl WasmAbi for WasmMutSlice {
78 type Prim1 = <WasmSlice as WasmAbi>::Prim1;
80 type Prim2 = <WasmSlice as WasmAbi>::Prim2;
82 type Prim3 = u32;
84 type Prim4 = ();
85
86 #[inline]
87 fn split(self) -> (Self::Prim1, Self::Prim2, u32, ()) {
88 let (ptr, len, (), ()) = self.slice.split();
89 (ptr, len, self.idx, ())
90 }
91
92 #[inline]
93 fn join(ptr: Self::Prim1, len: Self::Prim2, idx: u32, _: ()) -> Self {
94 Self {
95 slice: WasmSlice::join(ptr, len, (), ()),
96 idx,
97 }
98 }
99}
100
101pub struct MutSlice<T> {
103 contents: Box<[T]>,
105 js: JsValue,
107}
108
109impl<T> Drop for MutSlice<T> {
110 fn drop(&mut self) {
111 let byte_slice = unsafe {
112 core::slice::from_raw_parts(
113 self.contents.as_ptr() as *const u8,
114 self.contents.len() * mem::size_of::<T>(),
115 )
116 };
117 __wbindgen_copy_to_typed_array(byte_slice, &self.js);
118 }
119}
120
121impl<T> Deref for MutSlice<T> {
122 type Target = [T];
123
124 fn deref(&self) -> &[T] {
125 &self.contents
126 }
127}
128
129impl<T> DerefMut for MutSlice<T> {
130 fn deref_mut(&mut self) -> &mut [T] {
131 &mut self.contents
132 }
133}
134
135macro_rules! vectors {
136 ($($t:ty)*) => ($(
137 vectors_internal!($t);
138 vectors_internal!(MaybeUninit<$t>);
139 )*)
140}
141
142macro_rules! vectors_internal {
143 ($t:ty) => {
144 impl WasmDescribeVector for $t {
145 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
146 fn describe_vector() {
147 inform(VECTOR);
148 <$t>::describe();
149 }
150 }
151
152 impl VectorIntoWasmAbi for $t {
153 type Abi = WasmSlice;
154
155 #[inline]
156 fn vector_into_abi(vector: Box<[$t]>) -> WasmSlice {
157 let ptr = vector.as_ptr();
158 let len = vector.len();
159 mem::forget(vector);
160 WasmSlice::from_usize(ptr as usize, len)
161 }
162 }
163
164 impl VectorFromWasmAbi for $t {
165 type Abi = WasmSlice;
166
167 #[inline]
168 unsafe fn vector_from_abi(js: WasmSlice) -> Box<[$t]> {
169 let ptr = js.ptr.into_usize() as *mut $t;
170 let len = js.len.into_usize();
171 Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
172 }
173 }
174
175 impl<'a> IntoWasmAbi for &'a [$t] {
176 type Abi = WasmSlice;
177
178 #[inline]
179 fn into_abi(self) -> WasmSlice {
180 WasmSlice::from_usize(self.as_ptr() as usize, self.len())
181 }
182 }
183
184 impl<'a> OptionIntoWasmAbi for &'a [$t] {
185 #[inline]
186 fn none() -> WasmSlice {
187 null_slice()
188 }
189 }
190
191 impl<'a> IntoWasmAbi for &'a mut [$t] {
192 type Abi = WasmSlice;
193
194 #[inline]
195 fn into_abi(self) -> WasmSlice {
196 (&*self).into_abi()
197 }
198 }
199
200 impl<'a> OptionIntoWasmAbi for &'a mut [$t] {
201 #[inline]
202 fn none() -> WasmSlice {
203 null_slice()
204 }
205 }
206
207 impl RefFromWasmAbi for [$t] {
208 type Abi = WasmSlice;
209 type Anchor = Box<[$t]>;
210
211 #[inline]
212 unsafe fn ref_from_abi(js: WasmSlice) -> Box<[$t]> {
213 <Box<[$t]>>::from_abi(js)
214 }
215 }
216
217 impl RefMutFromWasmAbi for [$t] {
218 type Abi = WasmMutSlice;
219 type Anchor = MutSlice<$t>;
220
221 #[inline]
222 unsafe fn ref_mut_from_abi(js: WasmMutSlice) -> MutSlice<$t> {
223 let contents = <Box<[$t]>>::from_abi(js.slice);
224 let js = JsValue::from_abi(js.idx);
225 MutSlice { contents, js }
226 }
227 }
228
229 impl LongRefFromWasmAbi for [$t] {
230 type Abi = WasmSlice;
231 type Anchor = Box<[$t]>;
232
233 #[inline]
234 unsafe fn long_ref_from_abi(js: WasmSlice) -> Box<[$t]> {
235 Self::ref_from_abi(js)
236 }
237 }
238 };
239}
240
241vectors! {
242 u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64
243}
244
245impl WasmDescribeVector for String {
246 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
247 fn describe_vector() {
248 inform(VECTOR);
249 inform(NAMED_EXTERNREF);
250 inform(6);
252 inform('s' as u32);
253 inform('t' as u32);
254 inform('r' as u32);
255 inform('i' as u32);
256 inform('n' as u32);
257 inform('g' as u32);
258 }
259}
260
261impl VectorIntoWasmAbi for String {
262 type Abi = <Box<[JsValue]> as IntoWasmAbi>::Abi;
263
264 fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi {
265 js_value_vector_into_abi(vector)
266 }
267}
268
269impl VectorFromWasmAbi for String {
270 type Abi = <Box<[JsValue]> as FromWasmAbi>::Abi;
271
272 unsafe fn vector_from_abi(js: Self::Abi) -> Box<[Self]> {
273 js_value_vector_from_abi(js)
274 }
275}
276
277cfg_if! {
278 if #[cfg(feature = "enable-interning")] {
279 #[inline]
280 fn unsafe_get_cached_str(x: &str) -> Option<WasmSlice> {
281 crate::cache::intern::unsafe_get_str(x).map(|x| WasmSlice::from_usize(0, x as usize))
283 }
284
285 } else {
286 #[inline]
287 fn unsafe_get_cached_str(_x: &str) -> Option<WasmSlice> {
288 None
289 }
290 }
291}
292
293impl<T> IntoWasmAbi for Vec<T>
294where
295 Box<[T]>: IntoWasmAbi<Abi = WasmSlice>,
296{
297 type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
298
299 #[inline]
300 fn into_abi(self) -> Self::Abi {
301 self.into_boxed_slice().into_abi()
302 }
303}
304
305impl<T> OptionIntoWasmAbi for Vec<T>
306where
307 Box<[T]>: IntoWasmAbi<Abi = WasmSlice>,
308{
309 #[inline]
310 fn none() -> WasmSlice {
311 null_slice()
312 }
313}
314
315pub trait VectorRefIntoWasmAbi {
340 fn slice_into_abi(slice: &[Self]) -> WasmSlice
344 where
345 Self: Sized;
346
347 #[inline]
351 fn slice_none() -> WasmSlice
352 where
353 Self: Sized,
354 {
355 null_slice()
356 }
357}
358
359macro_rules! vector_ref_into_wasm_abi_primitive {
360 ($($t:ty)*) => ($(
361 impl VectorRefIntoWasmAbi for $t {
362 #[inline]
363 fn slice_into_abi(slice: &[Self]) -> WasmSlice {
364 WasmSlice::from_usize(slice.as_ptr() as usize, slice.len())
367 }
368 }
369 )*);
370}
371
372vector_ref_into_wasm_abi_primitive!(u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64);
373
374impl<T> VectorRefIntoWasmAbi for T
375where
376 for<'a> &'a T: Into<JsValue>,
377{
378 #[inline]
379 fn slice_into_abi(slice: &[Self]) -> WasmSlice {
380 let js_vals: Box<[JsValue]> = slice.iter().map(Into::into).collect();
385 js_vals.into_abi()
386 }
387}
388
389impl<T> FromWasmAbi for Vec<T>
390where
391 Box<[T]>: FromWasmAbi<Abi = WasmSlice>,
392{
393 type Abi = <Box<[T]> as FromWasmAbi>::Abi;
394
395 #[inline]
396 unsafe fn from_abi(js: Self::Abi) -> Self {
397 <Box<[T]>>::from_abi(js).into()
398 }
399}
400
401impl<T> OptionFromWasmAbi for Vec<T>
402where
403 Box<[T]>: FromWasmAbi<Abi = WasmSlice>,
404{
405 #[inline]
406 fn is_none(abi: &WasmSlice) -> bool {
407 abi.ptr.is_zero()
408 }
409}
410
411impl IntoWasmAbi for String {
412 type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
413
414 #[inline]
415 fn into_abi(self) -> Self::Abi {
416 unsafe_get_cached_str(&self).unwrap_or_else(|| self.into_bytes().into_abi())
419 }
420}
421
422impl OptionIntoWasmAbi for String {
423 #[inline]
424 fn none() -> Self::Abi {
425 null_slice()
426 }
427}
428
429impl FromWasmAbi for String {
430 type Abi = <Vec<u8> as FromWasmAbi>::Abi;
431
432 #[inline]
433 unsafe fn from_abi(js: Self::Abi) -> Self {
434 String::from_utf8_unchecked(<Vec<u8>>::from_abi(js))
435 }
436}
437
438impl OptionFromWasmAbi for String {
439 #[inline]
440 fn is_none(slice: &WasmSlice) -> bool {
441 slice.ptr.is_zero()
442 }
443}
444
445impl<'a> IntoWasmAbi for &'a str {
446 type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
447
448 #[inline]
449 fn into_abi(self) -> Self::Abi {
450 unsafe_get_cached_str(self).unwrap_or_else(|| self.as_bytes().into_abi())
453 }
454}
455
456impl OptionIntoWasmAbi for &str {
457 #[inline]
458 fn none() -> Self::Abi {
459 null_slice()
460 }
461}
462
463impl RefFromWasmAbi for str {
464 type Abi = <[u8] as RefFromWasmAbi>::Abi;
465 type Anchor = Box<str>;
466
467 #[inline]
468 unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
469 mem::transmute::<Box<[u8]>, Box<str>>(<Box<[u8]>>::from_abi(js))
470 }
471}
472
473impl LongRefFromWasmAbi for str {
474 type Abi = <[u8] as RefFromWasmAbi>::Abi;
475 type Anchor = Box<str>;
476
477 #[inline]
478 unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
479 Self::ref_from_abi(js)
480 }
481}
482
483unsafe impl ErasableGeneric for &str {
484 type Repr = &'static str;
485}
486
487unsafe impl<T: ErasableGeneric> ErasableGeneric for Box<[T]> {
488 type Repr = Box<[T::Repr]>;
489}
490
491impl UpcastFrom<&str> for &str {}
492
493impl<T, Target> UpcastFrom<Box<[T]>> for Box<[Target]> where Target: UpcastFrom<T> {}
494
495unsafe impl<T: ErasableGeneric> ErasableGeneric for Vec<T> {
496 type Repr = Vec<T::Repr>;
497}
498
499impl<T, Target> UpcastFrom<Vec<T>> for Vec<Target> where Target: UpcastFrom<T> {}
500
501impl<T: VectorIntoWasmAbi> IntoWasmAbi for Box<[T]> {
502 type Abi = <T as VectorIntoWasmAbi>::Abi;
503
504 fn into_abi(self) -> Self::Abi {
505 T::vector_into_abi(self)
506 }
507}
508
509impl<T> OptionIntoWasmAbi for Box<[T]>
510where
511 Self: IntoWasmAbi<Abi = WasmSlice>,
512{
513 fn none() -> WasmSlice {
514 null_slice()
515 }
516}
517
518impl<T: VectorFromWasmAbi> FromWasmAbi for Box<[T]> {
519 type Abi = <T as VectorFromWasmAbi>::Abi;
520
521 unsafe fn from_abi(js: Self::Abi) -> Self {
522 T::vector_from_abi(js)
523 }
524}
525
526impl<T> OptionFromWasmAbi for Box<[T]>
527where
528 Self: FromWasmAbi<Abi = WasmSlice>,
529{
530 fn is_none(slice: &WasmSlice) -> bool {
531 slice.ptr.is_zero()
532 }
533}
534
535impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> VectorFromWasmAbi for T {
536 type Abi = WasmSlice;
537
538 #[inline]
539 unsafe fn vector_from_abi(js: WasmSlice) -> Box<[Self]> {
540 let ptr = js.ptr.into_usize() as *mut T;
541 let len = js.len.into_usize();
542 Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
543 }
544}
545
546impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> VectorIntoWasmAbi for T {
547 type Abi = WasmSlice;
548
549 #[inline]
550 fn vector_into_abi(vector: Box<[T]>) -> WasmSlice {
551 let ptr = vector.as_ptr();
552 let len = vector.len();
553 mem::forget(vector);
554 WasmSlice::from_usize(ptr as usize, len)
555 }
556}
557
558unsafe impl<T: ErasableGeneric> ErasableGeneric for &[T] {
562 type Repr = &'static [T::Repr];
563}
564
565impl<'a, T, Target> UpcastFrom<&'a [T]> for &'a [Target] where Target: UpcastFrom<T> {}
566
567impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> IntoWasmAbi for &[T] {
568 type Abi = WasmSlice;
569
570 #[inline]
571 fn into_abi(self) -> WasmSlice {
572 WasmSlice::from_usize(self.as_ptr() as usize, self.len())
573 }
574}
575
576impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> OptionIntoWasmAbi for &[T] {
577 #[inline]
578 fn none() -> WasmSlice {
579 null_slice()
580 }
581}