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