use crate::artifact::{self, IntegrityError};
use std::sync::OnceLock;
use wasmtime::component::{Component, Linker};
use wasmtime::{Config, Engine, Store};
wasmtime::component::bindgen!({
path: "core/wit",
world: "aethel-core",
});
#[derive(Debug)]
pub enum LoadError {
Integrity(IntegrityError),
Runtime(wasmtime::Error),
}
impl core::fmt::Display for LoadError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
LoadError::Integrity(e) => write!(f, "{e}"),
LoadError::Runtime(e) => write!(f, "the embedded component failed to load: {e}"),
}
}
}
impl std::error::Error for LoadError {}
impl From<IntegrityError> for LoadError {
fn from(e: IntegrityError) -> Self {
LoadError::Integrity(e)
}
}
pub fn load() -> Result<(Store<()>, AethelCore), LoadError> {
shared()?.instantiate()
}
pub fn load_bytes(bytes: &[u8]) -> Result<(Store<()>, AethelCore), LoadError> {
Runtime::from_bytes(bytes)?.instantiate()
}
pub struct Runtime {
engine: Engine,
component: Component,
linker: Linker<()>,
}
impl Runtime {
pub fn new() -> Result<Self, LoadError> {
Self::from_bytes(artifact::COMPONENT)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, LoadError> {
artifact::verify(bytes)?;
let mut config = Config::new();
config.wasm_component_model(true);
let engine = Engine::new(&config).map_err(LoadError::Runtime)?;
let component = Component::from_binary(&engine, bytes).map_err(LoadError::Runtime)?;
let linker = Linker::new(&engine);
Ok(Runtime {
engine,
component,
linker,
})
}
pub fn instantiate(&self) -> Result<(Store<()>, AethelCore), LoadError> {
let mut store = Store::new(&self.engine, ());
let bindings = AethelCore::instantiate(&mut store, &self.component, &self.linker)
.map_err(LoadError::Runtime)?;
Ok((store, bindings))
}
}
pub fn shared() -> Result<&'static Runtime, LoadError> {
static SHARED: OnceLock<Runtime> = OnceLock::new();
if let Some(runtime) = SHARED.get() {
return Ok(runtime);
}
let runtime = Runtime::new()?;
Ok(SHARED.get_or_init(|| runtime))
}