use std::ops::{Deref, DerefMut};
use frunk::HList;
use super::{memory::Memory, RuntimeError};
use crate::memory_layout::FlatLayout;
pub trait Runtime: Sized {
type Export;
type Memory;
}
pub trait Instance: Sized {
type Runtime: Runtime;
type UserData;
type UserDataReference<'a>: Deref<Target = Self::UserData>
where
Self::UserData: 'a,
Self: 'a;
type UserDataMutReference<'a>: DerefMut<Target = Self::UserData>
where
Self::UserData: 'a,
Self: 'a;
fn load_export(&mut self, name: &str) -> Option<<Self::Runtime as Runtime>::Export>;
fn user_data(&self) -> Self::UserDataReference<'_>;
fn user_data_mut(&mut self) -> Self::UserDataMutReference<'_>;
}
pub trait InstanceWithFunction<Parameters, Results>: Instance
where
Parameters: FlatLayout,
Results: FlatLayout,
{
type Function;
fn function_from_export(
&mut self,
export: <Self::Runtime as Runtime>::Export,
) -> Result<Option<Self::Function>, RuntimeError>;
fn call(
&mut self,
function: &Self::Function,
parameters: Parameters,
) -> Result<Results, RuntimeError>;
fn load_function(&mut self, name: &str) -> Result<Self::Function, RuntimeError> {
let export = self
.load_export(name)
.ok_or_else(|| RuntimeError::FunctionNotFound(name.to_string()))?;
self.function_from_export(export)?
.ok_or_else(|| RuntimeError::NotAFunction(name.to_string()))
}
}
pub trait CabiReallocAlias: InstanceWithFunction<HList![i32, i32, i32, i32], HList![i32]> {}
impl<AnyInstance> CabiReallocAlias for AnyInstance where
AnyInstance: InstanceWithFunction<HList![i32, i32, i32, i32], HList![i32]>
{
}
pub trait CabiFreeAlias: InstanceWithFunction<HList![i32], HList![]> {}
impl<AnyInstance> CabiFreeAlias for AnyInstance where
AnyInstance: InstanceWithFunction<HList![i32], HList![]>
{
}
pub trait InstanceWithMemory: CabiReallocAlias + CabiFreeAlias {
fn memory_from_export(
&self,
export: <Self::Runtime as Runtime>::Export,
) -> Result<Option<<Self::Runtime as Runtime>::Memory>, RuntimeError>;
fn memory(&mut self) -> Result<Memory<'_, Self>, RuntimeError> {
let export = self
.load_export("memory")
.ok_or(RuntimeError::MissingMemory)?;
let memory = self
.memory_from_export(export)?
.ok_or(RuntimeError::NotMemory)?;
Ok(Memory::new(self, memory))
}
}