use crate::prelude::*;
use crate::Engine;
use anyhow::{anyhow, bail, Context, Result};
use std::borrow::Cow;
use std::path::Path;
pub struct CodeBuilder<'a> {
pub(super) engine: &'a Engine,
wasm: Option<Cow<'a, [u8]>>,
wasm_path: Option<Cow<'a, Path>>,
dwarf_package: Option<Cow<'a, [u8]>>,
dwarf_package_path: Option<Cow<'a, Path>>,
wat: bool,
}
impl<'a> CodeBuilder<'a> {
pub fn new(engine: &'a Engine) -> CodeBuilder<'a> {
CodeBuilder {
engine,
wasm: None,
wasm_path: None,
dwarf_package: None,
dwarf_package_path: None,
wat: cfg!(feature = "wat"),
}
}
pub fn wasm(&mut self, wasm_bytes: &'a [u8], wasm_path: Option<&'a Path>) -> Result<&mut Self> {
if self.wasm.is_some() {
bail!("cannot call `wasm` or `wasm_file` twice");
}
self.wasm = Some(wasm_bytes.into());
self.wasm_path = wasm_path.map(|p| p.into());
if self.wasm_path.is_some() {
self.dwarf_package_from_wasm_path()?;
}
Ok(self)
}
pub fn wat(&mut self, enable: bool) -> Result<&mut Self> {
if !cfg!(feature = "wat") && enable {
bail!("support for `wat` was disabled at compile time");
}
self.wat = enable;
Ok(self)
}
pub fn wasm_file(&mut self, file: &'a Path) -> Result<&mut Self> {
if self.wasm.is_some() {
bail!("cannot call `wasm` or `wasm_file` twice");
}
let wasm = std::fs::read(file)
.with_context(|| format!("failed to read input file: {}", file.display()))?;
self.wasm = Some(wasm.into());
self.wasm_path = Some(file.into());
self.dwarf_package_from_wasm_path()?;
Ok(self)
}
pub(super) fn wasm_binary(&self) -> Result<Cow<'_, [u8]>> {
let wasm = self
.wasm
.as_ref()
.ok_or_else(|| anyhow!("no wasm bytes have been configured"))?;
if self.wat {
#[cfg(feature = "wat")]
return wat::parse_bytes(wasm).map_err(|mut e| {
if let Some(path) = &self.wasm_path {
e.set_path(path);
}
e.into()
});
}
Ok((&wasm[..]).into())
}
pub fn dwarf_package_file(&mut self, file: &Path) -> Result<&mut Self> {
if self.dwarf_package.is_some() {
bail!("cannot call `dwarf_package` or `dwarf_package_file` twice");
}
let dwarf_package = std::fs::read(file)
.with_context(|| format!("failed to read dwarf input file: {}", file.display()))?;
self.dwarf_package_path = Some(Cow::Owned(file.to_owned()));
self.dwarf_package = Some(dwarf_package.into());
Ok(self)
}
fn dwarf_package_from_wasm_path(&mut self) -> Result<&mut Self> {
let dwarf_package_path_buf = self.wasm_path.as_ref().unwrap().with_extension("dwp");
if dwarf_package_path_buf.exists() {
return self.dwarf_package_file(dwarf_package_path_buf.as_path());
}
Ok(self)
}
pub(super) fn dwarf_package_binary(&self) -> Option<&[u8]> {
return self.dwarf_package.as_deref();
}
pub fn dwarf_package(&mut self, dwp_bytes: &'a [u8]) -> Result<&mut Self> {
if self.dwarf_package.is_some() {
bail!("cannot call `dwarf_package` or `dwarf_package_file` twice");
}
self.dwarf_package = Some(dwp_bytes.into());
Ok(self)
}
pub fn compile_module_serialized(&self) -> Result<Vec<u8>> {
let wasm = self.wasm_binary()?;
let dwarf_package = self.dwarf_package_binary();
let (v, _) = super::build_artifacts(self.engine, &wasm, dwarf_package.as_deref())?;
Ok(v)
}
#[cfg(feature = "component-model")]
pub fn compile_component_serialized(&self) -> Result<Vec<u8>> {
let bytes = self.wasm_binary()?;
let (v, _) = super::build_component_artifacts(self.engine, &bytes, None)?;
Ok(v)
}
}
pub struct HashedEngineCompileEnv<'a>(pub &'a Engine);
impl std::hash::Hash for HashedEngineCompileEnv<'_> {
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
let compiler = self.0.compiler();
compiler.triple().hash(hasher);
compiler.flags().hash(hasher);
compiler.isa_flags().hash(hasher);
let config = self.0.config();
self.0.tunables().hash(hasher);
config.features.hash(hasher);
config.wmemcheck.hash(hasher);
config.module_version.hash(hasher);
}
}