wasm_bridge_js/no_bindgen/
module.rs

1use std::borrow::Cow;
2
3use crate::{helpers::map_js_error, *};
4use anyhow::bail;
5use js_sys::{Uint8Array, WebAssembly};
6use wasm_bindgen_futures::JsFuture;
7
8#[derive(Clone, Debug)]
9pub struct Module {
10    pub(crate) module: WebAssembly::Module,
11}
12
13impl Module {
14    pub fn new(_engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Self> {
15        let bytes = Self::resolve_bytes(bytes.as_ref())?;
16        Self::from_bytes(&bytes)
17    }
18
19    pub async fn new_async(_engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Self> {
20        let bytes = Self::resolve_bytes(bytes.as_ref())?;
21        Self::from_bytes_async(&bytes).await
22    }
23
24    fn resolve_bytes(bytes: &[u8]) -> Result<Cow<[u8]>> {
25        if bytes.is_empty() {
26            bail!("Cannot create a module from empty bytes")
27        }
28
29        if let Ok(text) = std::str::from_utf8(bytes) {
30            Ok(Cow::Owned(Self::parse_wat(text)?))
31        } else {
32            Ok(Cow::Borrowed(bytes))
33        }
34    }
35
36    #[cfg(feature = "wat")]
37    fn parse_wat(wat: &str) -> Result<Vec<u8>> {
38        Ok(wat::parse_str(wat)?)
39    }
40
41    #[cfg(not(feature = "wat"))]
42    fn parse_wat(_wat: &str) -> Result<Vec<u8>> {
43        bail!("Module bytes are valid text, try enabling the 'wat' feature to parse it")
44    }
45
46    fn from_bytes(bytes: &[u8]) -> Result<Self> {
47        // TODO: view might be faster than from, but its unsafe
48        // Uint8Array::view(bytes.as_ref());
49        let byte_array = Uint8Array::from(bytes);
50
51        let module = WebAssembly::Module::new(&byte_array.into())
52            .map_err(map_js_error("Failed to compile bytes to a WASM module"))?;
53
54        Ok(Self { module })
55    }
56
57    async fn from_bytes_async(bytes: &[u8]) -> Result<Self> {
58        let byte_array = Uint8Array::from(bytes);
59        let promise = WebAssembly::compile(&byte_array);
60
61        let module = JsFuture::from(promise)
62            .await
63            .map_err(map_js_error("Failed to compile bytes to a WASM module"))?;
64
65        Ok(Self {
66            module: module.into(),
67        })
68    }
69}
70
71pub async fn new_module_async(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
72    Module::new_async(engine, bytes).await
73}