wasm_bindgen/convert/
slices.rs1use 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;
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: u32,
32 pub len: u32,
33}
34
35impl WasmAbi for WasmSlice {
36 type Prim1 = u32;
38 type Prim2 = u32;
40 type Prim3 = ();
41 type Prim4 = ();
42
43 #[inline]
44 fn split(self) -> (u32, u32, (), ()) {
45 (self.ptr, self.len, (), ())
46 }
47
48 #[inline]
49 fn join(ptr: u32, len: u32, _: (), _: ()) -> Self {
50 Self { ptr, len }
51 }
52}
53
54#[inline]
55fn null_slice() -> WasmSlice {
56 WasmSlice { ptr: 0, len: 0 }
57}
58
59pub struct WasmMutSlice {
60 pub slice: WasmSlice,
61 pub idx: u32,
62}
63
64impl WasmAbi for WasmMutSlice {
65 type Prim1 = u32;
67 type Prim2 = u32;
69 type Prim3 = u32;
71 type Prim4 = ();
72
73 #[inline]
74 fn split(self) -> (u32, u32, u32, ()) {
75 (self.slice.ptr, self.slice.len, self.idx, ())
76 }
77
78 #[inline]
79 fn join(ptr: u32, len: u32, idx: u32, _: ()) -> Self {
80 Self {
81 slice: WasmSlice { ptr, len },
82 idx,
83 }
84 }
85}
86
87pub struct MutSlice<T> {
89 contents: Box<[T]>,
91 js: JsValue,
93}
94
95impl<T> Drop for MutSlice<T> {
96 fn drop(&mut self) {
97 let byte_slice = unsafe {
98 core::slice::from_raw_parts(
99 self.contents.as_ptr() as *const u8,
100 self.contents.len() * mem::size_of::<T>(),
101 )
102 };
103 __wbindgen_copy_to_typed_array(byte_slice, &self.js);
104 }
105}
106
107impl<T> Deref for MutSlice<T> {
108 type Target = [T];
109
110 fn deref(&self) -> &[T] {
111 &self.contents
112 }
113}
114
115impl<T> DerefMut for MutSlice<T> {
116 fn deref_mut(&mut self) -> &mut [T] {
117 &mut self.contents
118 }
119}
120
121macro_rules! vectors {
122 ($($t:ty)*) => ($(
123 vectors_internal!($t);
124 vectors_internal!(MaybeUninit<$t>);
125 )*)
126}
127
128macro_rules! vectors_internal {
129 ($t:ty) => {
130 impl WasmDescribeVector for $t {
131 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
132 fn describe_vector() {
133 inform(VECTOR);
134 <$t>::describe();
135 }
136 }
137
138 impl VectorIntoWasmAbi for $t {
139 type Abi = WasmSlice;
140
141 #[inline]
142 fn vector_into_abi(vector: Box<[$t]>) -> WasmSlice {
143 let ptr = vector.as_ptr();
144 let len = vector.len();
145 mem::forget(vector);
146 WasmSlice {
147 ptr: ptr.into_abi(),
148 len: len as u32,
149 }
150 }
151 }
152
153 impl VectorFromWasmAbi for $t {
154 type Abi = WasmSlice;
155
156 #[inline]
157 unsafe fn vector_from_abi(js: WasmSlice) -> Box<[$t]> {
158 let ptr = <*mut $t>::from_abi(js.ptr);
159 let len = js.len as usize;
160 Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
161 }
162 }
163
164 impl<'a> IntoWasmAbi for &'a [$t] {
165 type Abi = WasmSlice;
166
167 #[inline]
168 fn into_abi(self) -> WasmSlice {
169 WasmSlice {
170 ptr: self.as_ptr().into_abi(),
171 len: self.len() as u32,
172 }
173 }
174 }
175
176 impl<'a> OptionIntoWasmAbi for &'a [$t] {
177 #[inline]
178 fn none() -> WasmSlice {
179 null_slice()
180 }
181 }
182
183 impl<'a> IntoWasmAbi for &'a mut [$t] {
184 type Abi = WasmSlice;
185
186 #[inline]
187 fn into_abi(self) -> WasmSlice {
188 (&*self).into_abi()
189 }
190 }
191
192 impl<'a> OptionIntoWasmAbi for &'a mut [$t] {
193 #[inline]
194 fn none() -> WasmSlice {
195 null_slice()
196 }
197 }
198
199 impl RefFromWasmAbi for [$t] {
200 type Abi = WasmSlice;
201 type Anchor = Box<[$t]>;
202
203 #[inline]
204 unsafe fn ref_from_abi(js: WasmSlice) -> Box<[$t]> {
205 <Box<[$t]>>::from_abi(js)
206 }
207 }
208
209 impl RefMutFromWasmAbi for [$t] {
210 type Abi = WasmMutSlice;
211 type Anchor = MutSlice<$t>;
212
213 #[inline]
214 unsafe fn ref_mut_from_abi(js: WasmMutSlice) -> MutSlice<$t> {
215 let contents = <Box<[$t]>>::from_abi(js.slice);
216 let js = JsValue::from_abi(js.idx);
217 MutSlice { contents, js }
218 }
219 }
220
221 impl LongRefFromWasmAbi for [$t] {
222 type Abi = WasmSlice;
223 type Anchor = Box<[$t]>;
224
225 #[inline]
226 unsafe fn long_ref_from_abi(js: WasmSlice) -> Box<[$t]> {
227 Self::ref_from_abi(js)
228 }
229 }
230 };
231}
232
233vectors! {
234 u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64
235}
236
237impl WasmDescribeVector for String {
238 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
239 fn describe_vector() {
240 inform(VECTOR);
241 inform(NAMED_EXTERNREF);
242 inform(6);
244 inform('s' as u32);
245 inform('t' as u32);
246 inform('r' as u32);
247 inform('i' as u32);
248 inform('n' as u32);
249 inform('g' as u32);
250 }
251}
252
253impl VectorIntoWasmAbi for String {
254 type Abi = <Box<[JsValue]> as IntoWasmAbi>::Abi;
255
256 fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi {
257 js_value_vector_into_abi(vector)
258 }
259}
260
261impl VectorFromWasmAbi for String {
262 type Abi = <Box<[JsValue]> as FromWasmAbi>::Abi;
263
264 unsafe fn vector_from_abi(js: Self::Abi) -> Box<[Self]> {
265 js_value_vector_from_abi(js)
266 }
267}
268
269cfg_if! {
270 if #[cfg(feature = "enable-interning")] {
271 #[inline]
272 fn unsafe_get_cached_str(x: &str) -> Option<WasmSlice> {
273 crate::cache::intern::unsafe_get_str(x).map(|x| WasmSlice { ptr: 0, len: x })
275 }
276
277 } else {
278 #[inline]
279 fn unsafe_get_cached_str(_x: &str) -> Option<WasmSlice> {
280 None
281 }
282 }
283}
284
285impl<T> IntoWasmAbi for Vec<T>
286where
287 Box<[T]>: IntoWasmAbi<Abi = WasmSlice>,
288{
289 type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
290
291 #[inline]
292 fn into_abi(self) -> Self::Abi {
293 self.into_boxed_slice().into_abi()
294 }
295}
296
297impl<T> OptionIntoWasmAbi for Vec<T>
298where
299 Box<[T]>: IntoWasmAbi<Abi = WasmSlice>,
300{
301 #[inline]
302 fn none() -> WasmSlice {
303 null_slice()
304 }
305}
306
307impl<T> FromWasmAbi for Vec<T>
308where
309 Box<[T]>: FromWasmAbi<Abi = WasmSlice>,
310{
311 type Abi = <Box<[T]> as FromWasmAbi>::Abi;
312
313 #[inline]
314 unsafe fn from_abi(js: Self::Abi) -> Self {
315 <Box<[T]>>::from_abi(js).into()
316 }
317}
318
319impl<T> OptionFromWasmAbi for Vec<T>
320where
321 Box<[T]>: FromWasmAbi<Abi = WasmSlice>,
322{
323 #[inline]
324 fn is_none(abi: &WasmSlice) -> bool {
325 abi.ptr == 0
326 }
327}
328
329impl IntoWasmAbi for String {
330 type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
331
332 #[inline]
333 fn into_abi(self) -> Self::Abi {
334 unsafe_get_cached_str(&self).unwrap_or_else(|| self.into_bytes().into_abi())
337 }
338}
339
340impl OptionIntoWasmAbi for String {
341 #[inline]
342 fn none() -> Self::Abi {
343 null_slice()
344 }
345}
346
347impl FromWasmAbi for String {
348 type Abi = <Vec<u8> as FromWasmAbi>::Abi;
349
350 #[inline]
351 unsafe fn from_abi(js: Self::Abi) -> Self {
352 String::from_utf8_unchecked(<Vec<u8>>::from_abi(js))
353 }
354}
355
356impl OptionFromWasmAbi for String {
357 #[inline]
358 fn is_none(slice: &WasmSlice) -> bool {
359 slice.ptr == 0
360 }
361}
362
363impl<'a> IntoWasmAbi for &'a str {
364 type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
365
366 #[inline]
367 fn into_abi(self) -> Self::Abi {
368 unsafe_get_cached_str(self).unwrap_or_else(|| self.as_bytes().into_abi())
371 }
372}
373
374impl OptionIntoWasmAbi for &str {
375 #[inline]
376 fn none() -> Self::Abi {
377 null_slice()
378 }
379}
380
381impl RefFromWasmAbi for str {
382 type Abi = <[u8] as RefFromWasmAbi>::Abi;
383 type Anchor = Box<str>;
384
385 #[inline]
386 unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
387 mem::transmute::<Box<[u8]>, Box<str>>(<Box<[u8]>>::from_abi(js))
388 }
389}
390
391impl LongRefFromWasmAbi for str {
392 type Abi = <[u8] as RefFromWasmAbi>::Abi;
393 type Anchor = Box<str>;
394
395 #[inline]
396 unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
397 Self::ref_from_abi(js)
398 }
399}
400
401unsafe impl ErasableGeneric for &str {
402 type Repr = &'static str;
403}
404
405unsafe impl<T: ErasableGeneric> ErasableGeneric for Box<[T]> {
406 type Repr = Box<[T::Repr]>;
407}
408
409impl UpcastFrom<&str> for &str {}
410
411impl<T, Target> UpcastFrom<Box<[T]>> for Box<[Target]> where Target: UpcastFrom<T> {}
412
413unsafe impl<T: ErasableGeneric> ErasableGeneric for Vec<T> {
414 type Repr = Vec<T::Repr>;
415}
416
417impl<T, Target> UpcastFrom<Vec<T>> for Vec<Target> where Target: UpcastFrom<T> {}
418
419impl<T: VectorIntoWasmAbi> IntoWasmAbi for Box<[T]> {
420 type Abi = <T as VectorIntoWasmAbi>::Abi;
421
422 fn into_abi(self) -> Self::Abi {
423 T::vector_into_abi(self)
424 }
425}
426
427impl<T> OptionIntoWasmAbi for Box<[T]>
428where
429 Self: IntoWasmAbi<Abi = WasmSlice>,
430{
431 fn none() -> WasmSlice {
432 null_slice()
433 }
434}
435
436impl<T: VectorFromWasmAbi> FromWasmAbi for Box<[T]> {
437 type Abi = <T as VectorFromWasmAbi>::Abi;
438
439 unsafe fn from_abi(js: Self::Abi) -> Self {
440 T::vector_from_abi(js)
441 }
442}
443
444impl<T> OptionFromWasmAbi for Box<[T]>
445where
446 Self: FromWasmAbi<Abi = WasmSlice>,
447{
448 fn is_none(slice: &WasmSlice) -> bool {
449 slice.ptr == 0
450 }
451}
452
453impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> VectorFromWasmAbi for T {
454 type Abi = WasmSlice;
455
456 #[inline]
457 unsafe fn vector_from_abi(js: WasmSlice) -> Box<[Self]> {
458 let ptr = <*mut T>::from_abi(js.ptr);
459 let len = js.len as usize;
460 Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
461 }
462}
463
464impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> VectorIntoWasmAbi for T {
465 type Abi = WasmSlice;
466
467 #[inline]
468 fn vector_into_abi(vector: Box<[T]>) -> WasmSlice {
469 let ptr = vector.as_ptr();
470 let len = vector.len();
471 mem::forget(vector);
472 WasmSlice {
473 ptr: ptr.into_abi(),
474 len: len as u32,
475 }
476 }
477}
478
479unsafe impl<T: ErasableGeneric> ErasableGeneric for &[T] {
483 type Repr = &'static [T::Repr];
484}
485
486impl<'a, T, Target> UpcastFrom<&'a [T]> for &'a [Target] where Target: UpcastFrom<T> {}
487
488impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> IntoWasmAbi for &[T] {
489 type Abi = WasmSlice;
490
491 #[inline]
492 fn into_abi(self) -> WasmSlice {
493 WasmSlice {
494 ptr: self.as_ptr() as u32,
495 len: self.len() as u32,
496 }
497 }
498}
499
500impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> OptionIntoWasmAbi for &[T] {
501 #[inline]
502 fn none() -> WasmSlice {
503 null_slice()
504 }
505}