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