use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
use serde::{Serialize, Deserialize};
pub trait ToWasmValues {
fn to_wasm_values(&self) -> Vec<u8>;
}
pub trait FromWasmValues {
fn from_wasm_values(values: &[u8]) -> crate::Result<Self>
where
Self: Sized;
}
impl<T: Serialize> ToWasmValues for T {
fn to_wasm_values(&self) -> Vec<u8> {
rmp_serde::to_vec(self).unwrap_or_default()
}
}
impl<T: for<'de> Deserialize<'de>> FromWasmValues for T {
fn from_wasm_values(values: &[u8]) -> crate::Result<Self> {
rmp_serde::from_slice(values).map_err(|e| {
crate::Error::Serialization {
format: "messagepack".to_string(),
operation: "deserialize".to_string(),
reason: e.to_string(),
}
})
}
}
pub struct MemoryTracker {
current: AtomicU64,
peak: AtomicU64,
}
impl MemoryTracker {
pub fn new() -> Self {
Self {
current: AtomicU64::new(0),
peak: AtomicU64::new(0),
}
}
pub fn allocate(&self, size: u64) {
let current = self.current.fetch_add(size, Ordering::SeqCst) + size;
let mut peak = self.peak.load(Ordering::SeqCst);
while current > peak {
match self.peak.compare_exchange_weak(
peak,
current,
Ordering::SeqCst,
Ordering::SeqCst,
) {
Ok(_) => break,
Err(actual_peak) => peak = actual_peak,
}
}
}
pub fn deallocate(&self, size: u64) {
self.current.fetch_sub(size, Ordering::SeqCst);
}
pub fn current(&self) -> u64 {
self.current.load(Ordering::SeqCst)
}
pub fn peak(&self) -> u64 {
self.peak.load(Ordering::SeqCst)
}
pub fn reset_peak(&self) {
self.peak.store(self.current.load(Ordering::SeqCst), Ordering::SeqCst);
}
}
pub fn locate_wasi_modules() -> Vec<PathBuf> {
let mut paths = Vec::new();
let common_paths = [
"./wasi",
"./target/wasm32-wasi",
"/usr/local/lib/wasi",
"/usr/lib/wasi",
];
for path in common_paths.iter() {
let path = PathBuf::from(path);
if path.exists() {
paths.push(path);
}
}
if let Ok(path) = std::env::var("WASI_PATH") {
for p in path.split(':') {
let path = PathBuf::from(p);
if path.exists() {
paths.push(path);
}
}
}
paths
}
#[derive(Debug, Clone)]
pub struct CompilationOptions {
pub optimization_level: u8,
pub debug_info: bool,
pub validate: bool,
pub memory_alignment: Option<u64>,
pub consume_fuel: bool,
}
impl Default for CompilationOptions {
fn default() -> Self {
Self {
optimization_level: 1,
debug_info: false,
validate: true,
memory_alignment: None,
consume_fuel: true,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct MemoryRegion {
pub base: u32,
pub size: u32,
}
impl MemoryRegion {
pub fn new(base: u32, size: u32) -> Self {
Self { base, size }
}
pub fn contains(&self, addr: u32) -> bool {
addr >= self.base && addr < self.base + self.size
}
pub fn end(&self) -> u32 {
self.base + self.size
}
}
pub struct MemoryMap {
regions: Vec<MemoryRegion>,
size: u32,
}
impl MemoryMap {
pub fn new(size: u32) -> Self {
Self {
regions: Vec::new(),
size,
}
}
pub fn allocate(&mut self, size: u32, align: u32) -> Option<u32> {
if size == 0 {
return Some(0);
}
let align_mask = align - 1;
let mut base = 0;
while base < self.size {
let aligned_base = (base + align_mask) & !align_mask;
if aligned_base + size > self.size {
return None;
}
let mut is_free = true;
for region in &self.regions {
if region.contains(aligned_base) ||
region.contains(aligned_base + size - 1) ||
(aligned_base <= region.base && aligned_base + size >= region.end()) {
is_free = false;
base = region.end();
break;
}
}
if is_free {
let region = MemoryRegion::new(aligned_base, size);
self.regions.push(region);
return Some(aligned_base);
}
}
None
}
pub fn free(&mut self, base: u32) {
self.regions.retain(|region| region.base != base);
}
pub fn is_allocated(&self, addr: u32) -> bool {
self.regions.iter().any(|region| region.contains(addr))
}
pub fn get_region(&self, addr: u32) -> Option<MemoryRegion> {
self.regions.iter()
.find(|region| region.contains(addr))
.copied()
}
}
#[derive(Debug, Clone, Default)]
pub struct ImportConfig {
pub host_functions: Vec<HostFunction>,
pub memory: Option<MemoryConfig>,
}
#[derive(Debug, Clone)]
pub struct MemoryConfig {
pub min_pages: u32,
pub max_pages: Option<u32>,
pub shared: bool,
}
#[derive(Debug, Clone)]
pub struct HostFunction {
pub module: String,
pub name: String,
pub params: Vec<WasmValueType>,
pub results: Vec<WasmValueType>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WasmValueType {
I32,
I64,
F32,
F64,
V128,
FuncRef,
ExternRef,
}