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