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