use crate::Engine;
use anyhow::{Context, Result};
use std::{path::Path, sync::Arc};
#[derive(Clone)]
pub struct Module {
inner: Arc<compiler::Module>,
}
impl std::fmt::Debug for Module {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Module")
.field("functions", &self.inner.program().functions.len())
.field("entry_point", &format_args!("{:#x}", self.entry_point()))
.field("memory_size", &format_args!("{:#x}", self.memory_size()))
.finish()
}
}
impl Module {
pub fn new(engine: &Engine, bytes: &[u8]) -> Result<Module> {
let program = rv::elf::load(bytes).context("failed to load the guest image")?;
let inner = compiler::Module::new(
engine.compiler(),
program,
engine.config().memory_size,
engine.config().interruptible,
)?;
Ok(Module {
inner: Arc::new(inner),
})
}
pub fn from_file(engine: &Engine, path: impl AsRef<Path>) -> Result<Module> {
let path = path.as_ref();
let bytes =
std::fs::read(path).with_context(|| format!("failed to read {}", path.display()))?;
Module::new(engine, &bytes).with_context(|| format!("failed to compile {}", path.display()))
}
pub fn exports(&self) -> impl Iterator<Item = &str> {
self.inner
.program()
.functions
.values()
.map(|f| f.name.as_str())
}
pub fn entry_point(&self) -> u64 {
self.inner.program().entry
}
pub fn interruptible(&self) -> bool {
self.inner.interruptible()
}
pub fn memory_size(&self) -> u64 {
self.inner.memory_size()
}
pub(crate) fn inner(&self) -> &Arc<compiler::Module> {
&self.inner
}
}