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