use anyhow::{Context, Result, anyhow};
use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Mutex};
use wasmtime::{Config, Engine, Instance, Linker, Module, Store};
use std::time::{Duration, Instant};
use std::hash::Hasher;
#[derive(Debug)]
pub struct WasmModule {
instance: Instance,
id: String,
load_time: std::time::Duration,
size: usize,
}
impl PartialEq for WasmModule {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.load_time == other.load_time
&& self.size == other.size
}
}
impl WasmModule {
pub fn instance(&self) -> &Instance {
&self.instance
}
pub fn id(&self) -> &str {
&self.id
}
pub fn load_time(&self) -> std::time::Duration {
self.load_time
}
pub fn size(&self) -> usize {
self.size
}
}
pub struct WasmModuleLoader {
engine: Arc<Engine>,
config: LoaderConfig,
}
#[derive(Debug, Clone)]
struct LoaderConfig {
max_module_size: usize,
enable_validation: bool,
enable_parallel: bool,
}
impl Default for LoaderConfig {
fn default() -> Self {
Self {
max_module_size: 100 * 1024 * 1024, enable_validation: true,
enable_parallel: true,
}
}
}
impl WasmModuleLoader {
pub fn new() -> Result<Self> {
let config: _ = Config::default();
let engine: _ = Arc::new(Mutex::new(Engine::new(&config)))
.context("Failed to create Wasmtime engine for module loader")?;
Ok(WasmModuleLoader {
engine,
config: LoaderConfig::default(),
})
}
pub fn new_with_config(
max_module_size: usize,
enable_validation: bool,
enable_parallel: bool,
) -> Result<Self> {
let config: _ = Config::default();
let engine: _ = Arc::new(Mutex::new(Engine::new(&config)))
.context("Failed to create Wasmtime engine")?;
Ok(WasmModuleLoader {
engine,
config: LoaderConfig {
max_module_size,
enable_validation,
enable_parallel,
},
})
}
pub fn load_module(&self, wasm_bytes: &[u8]) -> Result<WasmModule> {
let start: _ = Instant::now();
if wasm_bytes.len() > self.config.max_module_size {
return Err(anyhow!(
"Module size {} exceeds maximum allowed size {}",
wasm_bytes.len(),
self.config.max_module_size
));
}
if self.config.enable_validation {
Module::validate(&self.engine, wasm_bytes)
.context("WASM module validation failed")?;
}
let module: _ = Module::new(&self.engine, wasm_bytes)
.context("Failed to compile WASM module")?;
let mut store: Store<()> = Store::new(&self.engine, ());
let linker: Linker<()> = Linker::new(&self.engine);
let instance: _ = linker
.instantiate(&mut store, &module)
.context("Failed to instantiate WASM module")?;
let id: _ = self.generate_module_id(wasm_bytes)?;
let load_time: _ = start.elapsed();
let size: _ = wasm_bytes.len();
Ok(WasmModule {
instance,
id,
load_time,
size,
})
}
pub fn load_module_from_file(&self, file_path: &str) -> Result<WasmModule> {
let wasm_bytes: _ = std::fs::read(file_path)
.context(format!("Failed to read WASM file: {}", file_path))?;
self.load_module(&wasm_bytes)
}
pub fn prewarm_modules(&self, wasm_bytes_list: Vec<Vec<u8>>) -> Result<Vec<WasmModule>> {
let mut modules = Vec::with_capacity(wasm_bytes_list.len());
for wasm_bytes in wasm_bytes_list {
let module: _ = self.load_module(&wasm_bytes)?;
modules.push(module);
}
Ok(modules)
}
pub fn engine(&self) -> &Arc<Engine> {
&self.engine
}
fn generate_module_id(&self, wasm_bytes: &[u8]) -> Result<String> {
let mut hasher = Hasher::new();
hasher.update(wasm_bytes);
let hash: _ = hasher.finalize();
Ok(hash.to_hex().to_string())
}
pub fn get_stats(&self) -> LoaderStats {
LoaderStats {
max_module_size: self.config.max_module_size,
enable_validation: self.config.enable_validation,
enable_parallel: self.config.enable_parallel,
engine_info: format!("Wasmtime Engine v38.0"),
}
}
}
#[derive(Debug, Clone)]
pub struct LoaderStats {
pub max_module_size: usize,
pub enable_validation: bool,
pub enable_parallel: bool,
pub engine_info: String,
}
impl std::fmt::Display for LoaderStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f,
"WasmModuleLoader Stats:\n\
- Max Module Size: {} MB\n\
- Validation: {}\n\
- Parallel Loading: {}\n\
- Engine: {}",
self.max_module_size / (1024 * 1024),
if self.enable_validation { "Enabled" } else { "Disabled" },
if self.enable_parallel { "Enabled" } else { "Disabled" },
self.engine_info
)
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_loader_creation() {
let loader: _ = WasmModuleLoader::new();
assert!(loader.is_ok());
}
#[test]
fn test_loader_with_config() {
let loader: _ = WasmModuleLoader::new_with_config(
50 * 1024 * 1024, true,
true,
);
assert!(loader.is_ok());
}
#[test]
fn test_stats() {
let loader: _ = WasmModuleLoader::new().unwrap();
let stats: _ = loader.get_stats();
assert!(stats.max_module_size > 0);
assert!(stats.enable_validation);
}
fn create_minimal_wasm() -> Vec<u8> {
vec![
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, ]
}
}