1 | use crate::JsValue; |
2 | use core::borrow::{Borrow, BorrowMut}; |
3 | use core::cell::{Cell, UnsafeCell}; |
4 | use core::convert::Infallible; |
5 | use core::mem; |
6 | use core::ops::{Deref, DerefMut}; |
7 | #[cfg (target_feature = "atomics" )] |
8 | use core::sync::atomic::{AtomicU8, Ordering}; |
9 | |
10 | use alloc::alloc::{alloc, dealloc, realloc, Layout}; |
11 | use alloc::boxed::Box; |
12 | use alloc::rc::Rc; |
13 | use once_cell::unsync::Lazy; |
14 | |
15 | pub extern crate alloc; |
16 | pub extern crate core; |
17 | #[cfg (feature = "std" )] |
18 | pub extern crate std; |
19 | |
20 | pub mod marker; |
21 | |
22 | pub use wasm_bindgen_macro::BindgenedStruct; |
23 | |
24 | /// Wrapper around [`Lazy`] adding `Send + Sync` when `atomics` is not enabled. |
25 | pub struct LazyCell<T, F = fn() -> T>(Wrapper<Lazy<T, F>>); |
26 | |
27 | struct Wrapper<T>(T); |
28 | |
29 | unsafe impl<T> Sync for Wrapper<T> {} |
30 | |
31 | unsafe impl<T> Send for Wrapper<T> {} |
32 | |
33 | impl<T, F> LazyCell<T, F> { |
34 | pub const fn new(init: F) -> LazyCell<T, F> { |
35 | Self(Wrapper(Lazy::new(init))) |
36 | } |
37 | } |
38 | |
39 | impl<T, F: FnOnce() -> T> LazyCell<T, F> { |
40 | pub(crate) fn try_with<R>( |
41 | &self, |
42 | f: impl FnOnce(&T) -> R, |
43 | ) -> Result<R, core::convert::Infallible> { |
44 | Ok(f(&self.0 .0)) |
45 | } |
46 | |
47 | pub fn force(this: &Self) -> &T { |
48 | &this.0 .0 |
49 | } |
50 | } |
51 | |
52 | impl<T> Deref for LazyCell<T> { |
53 | type Target = T; |
54 | |
55 | fn deref(&self) -> &T { |
56 | ::once_cell::unsync::Lazy::force(&self.0 .0) |
57 | } |
58 | } |
59 | |
60 | #[cfg (not(target_feature = "atomics" ))] |
61 | pub use LazyCell as LazyLock; |
62 | |
63 | #[cfg (target_feature = "atomics" )] |
64 | pub struct LazyLock<T, F = fn() -> T> { |
65 | state: AtomicU8, |
66 | data: Wrapper<UnsafeCell<Data<T, F>>>, |
67 | } |
68 | |
69 | #[cfg (target_feature = "atomics" )] |
70 | enum Data<T, F> { |
71 | Value(T), |
72 | Init(F), |
73 | } |
74 | |
75 | #[cfg (target_feature = "atomics" )] |
76 | impl<T, F> LazyLock<T, F> { |
77 | const STATE_UNINIT: u8 = 0; |
78 | const STATE_INITIALIZING: u8 = 1; |
79 | const STATE_INIT: u8 = 2; |
80 | |
81 | pub const fn new(init: F) -> LazyLock<T, F> { |
82 | Self { |
83 | state: AtomicU8::new(Self::STATE_UNINIT), |
84 | data: Wrapper(UnsafeCell::new(Data::Init(init))), |
85 | } |
86 | } |
87 | } |
88 | |
89 | #[cfg (target_feature = "atomics" )] |
90 | impl<T> Deref for LazyLock<T> { |
91 | type Target = T; |
92 | |
93 | fn deref(&self) -> &T { |
94 | let mut state = self.state.load(Ordering::Acquire); |
95 | |
96 | loop { |
97 | match state { |
98 | Self::STATE_INIT => { |
99 | let Data::Value(value) = (unsafe { &*self.data.0.get() }) else { |
100 | unreachable!() |
101 | }; |
102 | return value; |
103 | } |
104 | Self::STATE_UNINIT => { |
105 | if let Err(new_state) = self.state.compare_exchange_weak( |
106 | Self::STATE_UNINIT, |
107 | Self::STATE_INITIALIZING, |
108 | Ordering::Acquire, |
109 | Ordering::Relaxed, |
110 | ) { |
111 | state = new_state; |
112 | continue; |
113 | } |
114 | |
115 | let data = unsafe { &mut *self.data.0.get() }; |
116 | let Data::Init(init) = data else { |
117 | unreachable!() |
118 | }; |
119 | *data = Data::Value(init()); |
120 | self.state.store(Self::STATE_INIT, Ordering::Release); |
121 | state = Self::STATE_INIT; |
122 | } |
123 | Self::STATE_INITIALIZING => { |
124 | // TODO: Block here if possible. This would require |
125 | // detecting if we can in the first place. |
126 | state = self.state.load(Ordering::Acquire); |
127 | } |
128 | _ => unreachable!(), |
129 | } |
130 | } |
131 | } |
132 | } |
133 | |
134 | #[macro_export ] |
135 | #[doc (hidden)] |
136 | #[cfg (not(target_feature = "atomics" ))] |
137 | macro_rules! __wbindgen_thread_local { |
138 | ($wasm_bindgen:tt, $actual_ty:ty) => {{ |
139 | static _VAL: $wasm_bindgen::__rt::LazyCell<$actual_ty> = |
140 | $wasm_bindgen::__rt::LazyCell::new(init); |
141 | $wasm_bindgen::JsThreadLocal { __inner: &_VAL } |
142 | }}; |
143 | } |
144 | |
145 | #[macro_export ] |
146 | #[doc (hidden)] |
147 | #[cfg (target_feature = "atomics" )] |
148 | #[allow_internal_unstable (thread_local)] |
149 | macro_rules! __wbindgen_thread_local { |
150 | ($wasm_bindgen:tt, $actual_ty:ty) => {{ |
151 | #[thread_local] |
152 | static _VAL: $wasm_bindgen::__rt::LazyCell<$actual_ty> = |
153 | $wasm_bindgen::__rt::LazyCell::new(init); |
154 | $wasm_bindgen::JsThreadLocal { |
155 | __inner: || unsafe { $wasm_bindgen::__rt::LazyCell::force(&_VAL) as *const $actual_ty }, |
156 | } |
157 | }}; |
158 | } |
159 | |
160 | #[macro_export ] |
161 | #[doc (hidden)] |
162 | #[cfg (not(wasm_bindgen_unstable_test_coverage))] |
163 | macro_rules! __wbindgen_coverage { |
164 | ($item:item) => { |
165 | $item |
166 | }; |
167 | } |
168 | |
169 | #[macro_export ] |
170 | #[doc (hidden)] |
171 | #[cfg (wasm_bindgen_unstable_test_coverage)] |
172 | #[allow_internal_unstable (coverage_attribute)] |
173 | macro_rules! __wbindgen_coverage { |
174 | ($item:item) => { |
175 | #[coverage(off)] |
176 | $item |
177 | }; |
178 | } |
179 | |
180 | #[inline ] |
181 | pub fn assert_not_null<T>(s: *mut T) { |
182 | if s.is_null() { |
183 | throw_null(); |
184 | } |
185 | } |
186 | |
187 | #[cold ] |
188 | #[inline (never)] |
189 | fn throw_null() -> ! { |
190 | super::throw_str("null pointer passed to rust" ); |
191 | } |
192 | |
193 | /// A vendored version of `RefCell` from the standard library. |
194 | /// |
195 | /// Now why, you may ask, would we do that? Surely `RefCell` in libstd is |
196 | /// quite good. And you're right, it is indeed quite good! Functionally |
197 | /// nothing more is needed from `RefCell` in the standard library but for |
198 | /// now this crate is also sort of optimizing for compiled code size. |
199 | /// |
200 | /// One major factor to larger binaries in Rust is when a panic happens. |
201 | /// Panicking in the standard library involves a fair bit of machinery |
202 | /// (formatting, panic hooks, synchronization, etc). It's all worthwhile if |
203 | /// you need it but for something like `WasmRefCell` here we don't actually |
204 | /// need all that! |
205 | /// |
206 | /// This is just a wrapper around all Rust objects passed to JS intended to |
207 | /// guard accidental reentrancy, so this vendored version is intended solely |
208 | /// to not panic in libstd. Instead when it "panics" it calls our `throw` |
209 | /// function in this crate which raises an error in JS. |
210 | pub struct WasmRefCell<T: ?Sized> { |
211 | borrow: Cell<usize>, |
212 | value: UnsafeCell<T>, |
213 | } |
214 | |
215 | impl<T: ?Sized> WasmRefCell<T> { |
216 | pub fn new(value: T) -> WasmRefCell<T> |
217 | where |
218 | T: Sized, |
219 | { |
220 | WasmRefCell { |
221 | value: UnsafeCell::new(value), |
222 | borrow: Cell::new(0), |
223 | } |
224 | } |
225 | |
226 | pub fn get_mut(&mut self) -> &mut T { |
227 | unsafe { &mut *self.value.get() } |
228 | } |
229 | |
230 | pub fn borrow(&self) -> Ref<T> { |
231 | unsafe { |
232 | if self.borrow.get() == usize::MAX { |
233 | borrow_fail(); |
234 | } |
235 | self.borrow.set(self.borrow.get() + 1); |
236 | Ref { |
237 | value: &*self.value.get(), |
238 | borrow: &self.borrow, |
239 | } |
240 | } |
241 | } |
242 | |
243 | pub fn borrow_mut(&self) -> RefMut<T> { |
244 | unsafe { |
245 | if self.borrow.get() != 0 { |
246 | borrow_fail(); |
247 | } |
248 | self.borrow.set(usize::MAX); |
249 | RefMut { |
250 | value: &mut *self.value.get(), |
251 | borrow: &self.borrow, |
252 | } |
253 | } |
254 | } |
255 | |
256 | pub fn into_inner(self) -> T |
257 | where |
258 | T: Sized, |
259 | { |
260 | self.value.into_inner() |
261 | } |
262 | } |
263 | |
264 | pub struct Ref<'b, T: ?Sized + 'b> { |
265 | value: &'b T, |
266 | borrow: &'b Cell<usize>, |
267 | } |
268 | |
269 | impl<T: ?Sized> Deref for Ref<'_, T> { |
270 | type Target = T; |
271 | |
272 | #[inline ] |
273 | fn deref(&self) -> &T { |
274 | self.value |
275 | } |
276 | } |
277 | |
278 | impl<T: ?Sized> Borrow<T> for Ref<'_, T> { |
279 | #[inline ] |
280 | fn borrow(&self) -> &T { |
281 | self.value |
282 | } |
283 | } |
284 | |
285 | impl<T: ?Sized> Drop for Ref<'_, T> { |
286 | fn drop(&mut self) { |
287 | self.borrow.set(self.borrow.get() - 1); |
288 | } |
289 | } |
290 | |
291 | pub struct RefMut<'b, T: ?Sized + 'b> { |
292 | value: &'b mut T, |
293 | borrow: &'b Cell<usize>, |
294 | } |
295 | |
296 | impl<T: ?Sized> Deref for RefMut<'_, T> { |
297 | type Target = T; |
298 | |
299 | #[inline ] |
300 | fn deref(&self) -> &T { |
301 | self.value |
302 | } |
303 | } |
304 | |
305 | impl<T: ?Sized> DerefMut for RefMut<'_, T> { |
306 | #[inline ] |
307 | fn deref_mut(&mut self) -> &mut T { |
308 | self.value |
309 | } |
310 | } |
311 | |
312 | impl<T: ?Sized> Borrow<T> for RefMut<'_, T> { |
313 | #[inline ] |
314 | fn borrow(&self) -> &T { |
315 | self.value |
316 | } |
317 | } |
318 | |
319 | impl<T: ?Sized> BorrowMut<T> for RefMut<'_, T> { |
320 | #[inline ] |
321 | fn borrow_mut(&mut self) -> &mut T { |
322 | self.value |
323 | } |
324 | } |
325 | |
326 | impl<T: ?Sized> Drop for RefMut<'_, T> { |
327 | fn drop(&mut self) { |
328 | self.borrow.set(val:0); |
329 | } |
330 | } |
331 | |
332 | fn borrow_fail() -> ! { |
333 | super::throw_str( |
334 | "recursive use of an object detected which would lead to \ |
335 | unsafe aliasing in rust" , |
336 | ); |
337 | } |
338 | |
339 | /// A type that encapsulates an `Rc<WasmRefCell<T>>` as well as a `Ref` |
340 | /// to the contents of that `WasmRefCell`. |
341 | /// |
342 | /// The `'static` requirement is an unfortunate consequence of how this |
343 | /// is implemented. |
344 | pub struct RcRef<T: ?Sized + 'static> { |
345 | // The 'static is a lie. |
346 | // |
347 | // We could get away without storing this, since we're in the same module as |
348 | // `WasmRefCell` and can directly manipulate its `borrow`, but I'm considering |
349 | // turning it into a wrapper around `std`'s `RefCell` to reduce `unsafe` in |
350 | // which case that would stop working. This also requires less `unsafe` as is. |
351 | // |
352 | // It's important that this goes before `Rc` so that it gets dropped first. |
353 | ref_: Ref<'static, T>, |
354 | _rc: Rc<WasmRefCell<T>>, |
355 | } |
356 | |
357 | impl<T: ?Sized> RcRef<T> { |
358 | pub fn new(rc: Rc<WasmRefCell<T>>) -> Self { |
359 | let ref_: Ref<'_, T> = unsafe { (*Rc::as_ptr(&rc)).borrow() }; |
360 | Self { _rc: rc, ref_ } |
361 | } |
362 | } |
363 | |
364 | impl<T: ?Sized> Deref for RcRef<T> { |
365 | type Target = T; |
366 | |
367 | #[inline ] |
368 | fn deref(&self) -> &T { |
369 | &self.ref_ |
370 | } |
371 | } |
372 | |
373 | impl<T: ?Sized> Borrow<T> for RcRef<T> { |
374 | #[inline ] |
375 | fn borrow(&self) -> &T { |
376 | &self.ref_ |
377 | } |
378 | } |
379 | |
380 | /// A type that encapsulates an `Rc<WasmRefCell<T>>` as well as a |
381 | /// `RefMut` to the contents of that `WasmRefCell`. |
382 | /// |
383 | /// The `'static` requirement is an unfortunate consequence of how this |
384 | /// is implemented. |
385 | pub struct RcRefMut<T: ?Sized + 'static> { |
386 | ref_: RefMut<'static, T>, |
387 | _rc: Rc<WasmRefCell<T>>, |
388 | } |
389 | |
390 | impl<T: ?Sized> RcRefMut<T> { |
391 | pub fn new(rc: Rc<WasmRefCell<T>>) -> Self { |
392 | let ref_: RefMut<'_, T> = unsafe { (*Rc::as_ptr(&rc)).borrow_mut() }; |
393 | Self { _rc: rc, ref_ } |
394 | } |
395 | } |
396 | |
397 | impl<T: ?Sized> Deref for RcRefMut<T> { |
398 | type Target = T; |
399 | |
400 | #[inline ] |
401 | fn deref(&self) -> &T { |
402 | &self.ref_ |
403 | } |
404 | } |
405 | |
406 | impl<T: ?Sized> DerefMut for RcRefMut<T> { |
407 | #[inline ] |
408 | fn deref_mut(&mut self) -> &mut T { |
409 | &mut self.ref_ |
410 | } |
411 | } |
412 | |
413 | impl<T: ?Sized> Borrow<T> for RcRefMut<T> { |
414 | #[inline ] |
415 | fn borrow(&self) -> &T { |
416 | &self.ref_ |
417 | } |
418 | } |
419 | |
420 | impl<T: ?Sized> BorrowMut<T> for RcRefMut<T> { |
421 | #[inline ] |
422 | fn borrow_mut(&mut self) -> &mut T { |
423 | &mut self.ref_ |
424 | } |
425 | } |
426 | |
427 | #[no_mangle ] |
428 | pub extern "C" fn __wbindgen_malloc(size: usize, align: usize) -> *mut u8 { |
429 | if let Ok(layout: Layout) = Layout::from_size_align(size, align) { |
430 | unsafe { |
431 | if layout.size() > 0 { |
432 | let ptr: *mut u8 = alloc(layout); |
433 | if !ptr.is_null() { |
434 | return ptr; |
435 | } |
436 | } else { |
437 | return align as *mut u8; |
438 | } |
439 | } |
440 | } |
441 | |
442 | malloc_failure(); |
443 | } |
444 | |
445 | #[no_mangle ] |
446 | pub unsafe extern "C" fn __wbindgen_realloc( |
447 | ptr: *mut u8, |
448 | old_size: usize, |
449 | new_size: usize, |
450 | align: usize, |
451 | ) -> *mut u8 { |
452 | debug_assert!(old_size > 0); |
453 | debug_assert!(new_size > 0); |
454 | if let Ok(layout: Layout) = Layout::from_size_align(old_size, align) { |
455 | let ptr: *mut u8 = realloc(ptr, layout, new_size); |
456 | if !ptr.is_null() { |
457 | return ptr; |
458 | } |
459 | } |
460 | malloc_failure(); |
461 | } |
462 | |
463 | #[cold ] |
464 | fn malloc_failure() -> ! { |
465 | cfg_if::cfg_if! { |
466 | if #[cfg(debug_assertions)] { |
467 | super::throw_str("invalid malloc request" ) |
468 | } else if #[cfg(feature = "std" )] { |
469 | std::process::abort(); |
470 | } else if #[cfg(all( |
471 | target_arch = "wasm32" , |
472 | any(target_os = "unknown" , target_os = "none" ) |
473 | ))] { |
474 | core::arch::wasm32::unreachable(); |
475 | } else { |
476 | unreachable!() |
477 | } |
478 | } |
479 | } |
480 | |
481 | #[no_mangle ] |
482 | pub unsafe extern "C" fn __wbindgen_free(ptr: *mut u8, size: usize, align: usize) { |
483 | // This happens for zero-length slices, and in that case `ptr` is |
484 | // likely bogus so don't actually send this to the system allocator |
485 | if size == 0 { |
486 | return; |
487 | } |
488 | let layout: Layout = Layout::from_size_align_unchecked(size, align); |
489 | dealloc(ptr, layout); |
490 | } |
491 | |
492 | /// This is a curious function necessary to get wasm-bindgen working today, |
493 | /// and it's a bit of an unfortunate hack. |
494 | /// |
495 | /// The general problem is that somehow we need the above two symbols to |
496 | /// exist in the final output binary (__wbindgen_malloc and |
497 | /// __wbindgen_free). These symbols may be called by JS for various |
498 | /// bindings, so we for sure need to make sure they're exported. |
499 | /// |
500 | /// The problem arises, though, when what if no Rust code uses the symbols? |
501 | /// For all intents and purposes it looks to LLVM and the linker like the |
502 | /// above two symbols are dead code, so they're completely discarded! |
503 | /// |
504 | /// Specifically what happens is this: |
505 | /// |
506 | /// * The above two symbols are generated into some object file inside of |
507 | /// libwasm_bindgen.rlib |
508 | /// * The linker, LLD, will not load this object file unless *some* symbol |
509 | /// is loaded from the object. In this case, if the Rust code never calls |
510 | /// __wbindgen_malloc or __wbindgen_free then the symbols never get linked |
511 | /// in. |
512 | /// * Later when `wasm-bindgen` attempts to use the symbols they don't |
513 | /// exist, causing an error. |
514 | /// |
515 | /// This function is a weird hack for this problem. We inject a call to this |
516 | /// function in all generated code. Usage of this function should then |
517 | /// ensure that the above two intrinsics are translated. |
518 | /// |
519 | /// Due to how rustc creates object files this function (and anything inside |
520 | /// it) will be placed into the same object file as the two intrinsics |
521 | /// above. That means if this function is called and referenced we'll pull |
522 | /// in the object file and link the intrinsics. |
523 | /// |
524 | /// Ideas for how to improve this are most welcome! |
525 | #[cfg_attr (wasm_bindgen_unstable_test_coverage, coverage(off))] |
526 | pub fn link_mem_intrinsics() { |
527 | crate::link::link_intrinsics(); |
528 | } |
529 | |
530 | #[cfg_attr (target_feature = "atomics" , thread_local)] |
531 | static GLOBAL_EXNDATA: Wrapper<Cell<[u32; 2]>> = Wrapper(Cell::new([0; 2])); |
532 | |
533 | #[no_mangle ] |
534 | pub unsafe extern "C" fn __wbindgen_exn_store(idx: u32) { |
535 | debug_assert_eq!(GLOBAL_EXNDATA.0.get()[0], 0); |
536 | GLOBAL_EXNDATA.0.set([1, idx]); |
537 | } |
538 | |
539 | pub fn take_last_exception() -> Result<(), super::JsValue> { |
540 | let ret: Result<(), JsValue> = if GLOBAL_EXNDATA.0.get()[0] == 1 { |
541 | Err(super::JsValue::_new(idx:GLOBAL_EXNDATA.0.get()[1])) |
542 | } else { |
543 | Ok(()) |
544 | }; |
545 | GLOBAL_EXNDATA.0.set([0, 0]); |
546 | ret |
547 | } |
548 | |
549 | /// An internal helper trait for usage in `#[wasm_bindgen]` on `async` |
550 | /// functions to convert the return value of the function to |
551 | /// `Result<JsValue, JsValue>` which is what we'll return to JS (where an |
552 | /// error is a failed future). |
553 | pub trait IntoJsResult { |
554 | fn into_js_result(self) -> Result<JsValue, JsValue>; |
555 | } |
556 | |
557 | impl IntoJsResult for () { |
558 | fn into_js_result(self) -> Result<JsValue, JsValue> { |
559 | Ok(JsValue::undefined()) |
560 | } |
561 | } |
562 | |
563 | impl<T: Into<JsValue>> IntoJsResult for T { |
564 | fn into_js_result(self) -> Result<JsValue, JsValue> { |
565 | Ok(self.into()) |
566 | } |
567 | } |
568 | |
569 | impl<T: Into<JsValue>, E: Into<JsValue>> IntoJsResult for Result<T, E> { |
570 | fn into_js_result(self) -> Result<JsValue, JsValue> { |
571 | match self { |
572 | Ok(e: T) => Ok(e.into()), |
573 | Err(e: E) => Err(e.into()), |
574 | } |
575 | } |
576 | } |
577 | |
578 | impl<E: Into<JsValue>> IntoJsResult for Result<(), E> { |
579 | fn into_js_result(self) -> Result<JsValue, JsValue> { |
580 | match self { |
581 | Ok(()) => Ok(JsValue::undefined()), |
582 | Err(e: E) => Err(e.into()), |
583 | } |
584 | } |
585 | } |
586 | |
587 | /// An internal helper trait for usage in `#[wasm_bindgen(start)]` |
588 | /// functions to throw the error (if it is `Err`). |
589 | pub trait Start { |
590 | fn start(self); |
591 | } |
592 | |
593 | impl Start for () { |
594 | #[inline ] |
595 | fn start(self) {} |
596 | } |
597 | |
598 | impl<E: Into<JsValue>> Start for Result<(), E> { |
599 | #[inline ] |
600 | fn start(self) { |
601 | if let Err(e: E) = self { |
602 | crate::throw_val(e.into()); |
603 | } |
604 | } |
605 | } |
606 | |
607 | /// An internal helper struct for usage in `#[wasm_bindgen(main)]` |
608 | /// functions to throw the error (if it is `Err`). |
609 | pub struct MainWrapper<T>(pub Option<T>); |
610 | |
611 | pub trait Main { |
612 | fn __wasm_bindgen_main(&mut self); |
613 | } |
614 | |
615 | impl Main for &mut &mut MainWrapper<()> { |
616 | #[inline ] |
617 | fn __wasm_bindgen_main(&mut self) {} |
618 | } |
619 | |
620 | impl Main for &mut &mut MainWrapper<Infallible> { |
621 | #[inline ] |
622 | fn __wasm_bindgen_main(&mut self) {} |
623 | } |
624 | |
625 | impl<E: Into<JsValue>> Main for &mut &mut MainWrapper<Result<(), E>> { |
626 | #[inline ] |
627 | fn __wasm_bindgen_main(&mut self) { |
628 | if let Err(e: E) = self.0.take().unwrap() { |
629 | crate::throw_val(e.into()); |
630 | } |
631 | } |
632 | } |
633 | |
634 | impl<E: core::fmt::Debug> Main for &mut MainWrapper<Result<(), E>> { |
635 | #[inline ] |
636 | fn __wasm_bindgen_main(&mut self) { |
637 | if let Err(e: E) = self.0.take().unwrap() { |
638 | crate::throw_str(&alloc::format!(" {:?}" , e)); |
639 | } |
640 | } |
641 | } |
642 | |
643 | pub const fn flat_len<T, const SIZE: usize>(slices: [&[T]; SIZE]) -> usize { |
644 | let mut len: usize = 0; |
645 | let mut i: usize = 0; |
646 | while i < slices.len() { |
647 | len += slices[i].len(); |
648 | i += 1; |
649 | } |
650 | len |
651 | } |
652 | |
653 | pub const fn flat_byte_slices<const RESULT_LEN: usize, const SIZE: usize>( |
654 | slices: [&[u8]; SIZE], |
655 | ) -> [u8; RESULT_LEN] { |
656 | let mut result: [u8; RESULT_LEN] = [0; RESULT_LEN]; |
657 | |
658 | let mut slice_index: usize = 0; |
659 | let mut result_offset: usize = 0; |
660 | |
661 | while slice_index < slices.len() { |
662 | let mut i: usize = 0; |
663 | let slice: &[u8] = slices[slice_index]; |
664 | while i < slice.len() { |
665 | result[result_offset] = slice[i]; |
666 | i += 1; |
667 | result_offset += 1; |
668 | } |
669 | slice_index += 1; |
670 | } |
671 | |
672 | result |
673 | } |
674 | |
675 | // NOTE: This method is used to encode u32 into a variable-length-integer during the compile-time . |
676 | // Generally speaking, the length of the encoded variable-length-integer depends on the size of the integer |
677 | // but the maximum capacity can be used here to simplify the amount of code during the compile-time . |
678 | pub const fn encode_u32_to_fixed_len_bytes(value: u32) -> [u8; 5] { |
679 | let mut result: [u8; 5] = [0; 5]; |
680 | let mut i: usize = 0; |
681 | while i < 4 { |
682 | result[i] = ((value >> (7 * i)) | 0x80) as u8; |
683 | i += 1; |
684 | } |
685 | result[4] = (value >> (7 * 4)) as u8; |
686 | result |
687 | } |
688 | |
689 | /// Trait for element types to implement `Into<JsValue>` for vectors of |
690 | /// themselves, which isn't possible directly thanks to the orphan rule. |
691 | pub trait VectorIntoJsValue: Sized { |
692 | fn vector_into_jsvalue(vector: Box<[Self]>) -> JsValue; |
693 | } |
694 | |
695 | impl<T: VectorIntoJsValue> From<Box<[T]>> for JsValue { |
696 | fn from(vector: Box<[T]>) -> Self { |
697 | T::vector_into_jsvalue(vector) |
698 | } |
699 | } |
700 | |
701 | pub fn js_value_vector_into_jsvalue<T: Into<JsValue>>(vector: Box<[T]>) -> JsValue { |
702 | let result: JsValue = unsafe { JsValue::_new(idx:super::__wbindgen_array_new()) }; |
703 | for value: T in vector.into_vec() { |
704 | let js: JsValue = value.into(); |
705 | unsafe { super::__wbindgen_array_push(array:result.idx, value:js.idx) } |
706 | // `__wbindgen_array_push` takes ownership over `js` and has already dropped it, |
707 | // so don't drop it again. |
708 | mem::forget(js); |
709 | } |
710 | result |
711 | } |
712 | |