use std::sync::{ Arc, Mutex };
use std::collections::{ HashMap, HashSet };
use wasmtime::component::{ Linker, ResourceType, Val };
use crate::{ Binding, PluginContext };
use crate::cardinality::Cardinality ;
use crate::linker::{ dispatch_all, dispatch_method };
use crate::resource_wrapper::ResourceWrapper ;
#[derive( Debug, Clone, Default )]
pub struct Interface {
functions: HashMap<String, Function>,
resources: HashSet<String>,
}
impl Interface {
pub fn new(
functions: HashMap<String, Function>,
resources: HashSet<String>,
) -> Self {
Self { functions, resources }
}
#[inline]
pub(crate) fn function( &self, name: &str ) -> Option<&Function> {
self.functions.get( name )
}
#[inline]
pub(crate) fn add_to_linker<PluginId, Ctx, Plugins>(
&self,
linker: &mut Linker<Ctx>,
interface_ident: &str,
binding: &Binding<PluginId, Ctx, Plugins>,
) -> Result<(), wasmtime::Error>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
Ctx: PluginContext,
Plugins: Cardinality<PluginId, crate::PluginInstance<Ctx>> + 'static,
<Plugins as Cardinality<PluginId, crate::PluginInstance<Ctx>>>::Rebind<Mutex<crate::PluginInstance<Ctx>>>: Send + Sync,
<Plugins as Cardinality<PluginId, crate::PluginInstance<Ctx>>>::Rebind<Mutex<crate::PluginInstance<Ctx>>>: Cardinality<PluginId, Mutex<crate::PluginInstance<Ctx>>>,
<<Plugins as Cardinality<PluginId, crate::PluginInstance<Ctx>>>::Rebind<Mutex<crate::PluginInstance<Ctx>>> as Cardinality<PluginId, Mutex<crate::PluginInstance<Ctx>>>>::Rebind<Val>: Into<Val>,
{
let mut linker_root = linker.root();
let mut linker_instance = linker_root.instance( interface_ident )?;
self.functions.iter().try_for_each(|( name, metadata )| {
let interface_ident_clone = interface_ident.to_string();
let binding_clone = binding.clone();
let name_clone = name.clone();
let metadata_clone = metadata.clone();
macro_rules! link {( $dispatch: expr ) => {
linker_instance.func_new( name, move | ctx, _ty, args, results | Ok(
results[0] = $dispatch( &binding_clone, ctx, &interface_ident_clone, &name_clone, &metadata_clone, args )
))
}}
match metadata.kind() {
FunctionKind::Freestanding => link!( dispatch_all ),
FunctionKind::Method => link!( dispatch_method ),
}
})?;
self.resources.iter().try_for_each(| resource | linker_instance
.resource( resource.as_str(), ResourceType::host::<Arc<ResourceWrapper<PluginId>>>(), ResourceWrapper::<PluginId>::drop )
)?;
Ok(())
}
}
#[derive( Debug, Clone, Copy, Eq, PartialEq )]
pub enum FunctionKind {
Freestanding,
Method,
}
#[derive( Debug, Clone )]
pub struct Function {
kind: FunctionKind,
return_kind: ReturnKind,
}
impl Function {
pub fn new(
kind: FunctionKind,
return_kind: ReturnKind,
) -> Self {
Self { kind, return_kind }
}
pub fn return_kind( &self ) -> ReturnKind { self.return_kind }
pub fn kind( &self ) -> FunctionKind { self.kind }
}
#[derive( Copy, Clone, Eq, PartialEq, Hash, Debug, Default )]
pub enum ReturnKind {
#[default] Void,
MayContainResources,
AssumeNoResources,
}
impl std::fmt::Display for ReturnKind {
fn fmt( &self, f: &mut std::fmt::Formatter ) -> Result<(), std::fmt::Error> {
match self {
Self::Void => write!( f, "Function returns no data" ),
Self::MayContainResources => write!( f, "Return type may contain resources" ),
Self::AssumeNoResources => write!( f, "Function is assumed to not return any resources" ),
}
}
}