use std::sync::Arc ;
use std::collections::HashMap ;
use futures::lock::Mutex ;
use wasmtime::component::{ Linker, Val };
use crate::{ Interface, PluginContext };
use crate::cardinality::{ Any, AtLeastOne, AtMostOne, Cardinality, ExactlyOne };
use crate::plugin_instance::{ PluginInstanceAsync, PluginInstanceSync };
type PluginSockets<PluginId, Plugins, Instance> =
<Plugins as Cardinality<PluginId, Instance>>::Rebind<Arc<Mutex<Instance>>> ;
type DispatchResults<PluginId, Plugins, Instance> =
<PluginSockets<PluginId, Plugins, Instance> as Cardinality<PluginId, Arc<Mutex<Instance>>>>::Rebind<
Result<wasmtime::component::Val, crate::DispatchError>
>;
type DispatchVals<PluginId, Plugins, Instance> =
<PluginSockets<PluginId, Plugins, Instance> as Cardinality<PluginId, Arc<Mutex<Instance>>>>::Rebind<
wasmtime::component::Val
>;
struct BindingData<PluginId, Plugins, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Instance: Send + 'static,
Plugins: Cardinality<PluginId, Instance>,
PluginSockets<PluginId, Plugins, Instance>: Send + Sync,
{
package_name: String,
interfaces: HashMap<String, Interface>,
plugins: PluginSockets<PluginId, Plugins, Instance>,
}
pub struct Binding<PluginId, Ctx, Plugins = ExactlyOne<PluginId, PluginInstanceSync<Ctx>>, Instance = PluginInstanceSync<Ctx>>(
Arc<BindingData<PluginId, Plugins, Instance>>,
std::marker::PhantomData<fn() -> Ctx>,
)
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
Plugins: Cardinality<PluginId, Instance> + 'static,
PluginSockets<PluginId, Plugins, Instance>: Send + Sync;
impl<PluginId, Ctx, Plugins, Instance> Clone for Binding<PluginId, Ctx, Plugins, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
Plugins: Cardinality<PluginId, Instance> + 'static,
PluginSockets<PluginId, Plugins, Instance>: Send + Sync,
{
fn clone( &self ) -> Self {
Self( Arc::clone( &self.0 ), std::marker::PhantomData )
}
}
impl<PluginId, Ctx, Plugins, Instance> std::fmt::Debug for Binding<PluginId, Ctx, Plugins, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + std::fmt::Debug + 'static,
Ctx: PluginContext + std::fmt::Debug + 'static,
Instance: Send + 'static,
Plugins: Cardinality<PluginId, Instance> + 'static,
PluginSockets<PluginId, Plugins, Instance>: Send + Sync + std::fmt::Debug,
{
fn fmt( &self, f: &mut std::fmt::Formatter<'_> ) -> std::fmt::Result {
f.debug_struct( "Binding" )
.field( "package_name", &self.0.package_name )
.field( "interfaces", &self.0.interfaces )
.field( "plugins", &self.0.plugins )
.finish()
}
}
impl<PluginId, Ctx, Plugins, Instance> Binding<PluginId, Ctx, Plugins, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
Plugins: Cardinality<PluginId, Instance> + 'static,
PluginSockets<PluginId, Plugins, Instance>: Cardinality<PluginId, Arc<Mutex<Instance>>> + Send + Sync,
{
pub fn new(
package_name: impl Into<String>,
interfaces: HashMap<String, Interface>,
plugins: Plugins
) -> Self {
Self( Arc::new( BindingData {
package_name: package_name.into(),
interfaces,
plugins: plugins.map_mut(| plugin | Arc::new( Mutex::new( plugin ))),
}), std::marker::PhantomData )
}
pub(crate) fn plugins( &self ) -> &PluginSockets<PluginId, Plugins, Instance> {
&self.0.plugins
}
}
impl<PluginId, Ctx, Plugins> Binding<PluginId, Ctx, Plugins, PluginInstanceSync<Ctx>>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Plugins: Cardinality<PluginId, PluginInstanceSync<Ctx>> + 'static,
PluginSockets<PluginId, Plugins, PluginInstanceSync<Ctx>>: Cardinality<PluginId, Arc<Mutex<PluginInstanceSync<Ctx>>>> + Send + Sync,
{
pub(crate) fn add_to_linker( binding: &Binding<PluginId, Ctx, Plugins>, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error>
where
PluginId: Into<Val>,
DispatchVals<PluginId, Plugins, PluginInstanceSync<Ctx>>: Into<Val>,
{
binding.0.interfaces.iter().try_for_each(|( name, interface )| {
let interface_ident = format!( "{}/{}", binding.0.package_name, name );
interface.add_to_linker( linker, &binding.0.package_name, &interface_ident, name, binding )
})
}
pub fn dispatch(
&self,
interface_name: &str,
function_name: &str,
args: &[wasmtime::component::Val],
) -> Result<DispatchResults<PluginId, Plugins, PluginInstanceSync<Ctx>>, crate::DispatchError> {
let interface = self.0.interfaces.get( interface_name )
.ok_or_else(|| crate::DispatchError::InvalidInterfacePath( format!( "{}/{}", self.0.package_name, interface_name )))?;
let function = interface.function( function_name )
.ok_or_else(|| crate::DispatchError::InvalidFunction( function_name.to_string() ))?;
Ok( self.0.plugins.map(| _, plugin | plugin
.try_lock().ok_or( crate::DispatchError::LockRejected )
.and_then(| mut lock | lock.dispatch(
&self.0.package_name,
interface_name,
function_name,
function,
args,
))
))
}
}
impl<PluginId, Ctx, Plugins> Binding<PluginId, Ctx, Plugins, PluginInstanceAsync<Ctx>>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Plugins: Cardinality<PluginId, PluginInstanceAsync<Ctx>> + 'static,
PluginSockets<PluginId, Plugins, PluginInstanceAsync<Ctx>>: Cardinality<PluginId, Arc<Mutex<PluginInstanceAsync<Ctx>>>> + Send + Sync,
{
pub(crate) fn add_to_linker_async( binding: &Self, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error>
where
PluginId: Into<Val>,
DispatchVals<PluginId, Plugins, PluginInstanceAsync<Ctx>>: Into<Val> + Send,
{
binding.0.interfaces.iter().try_for_each(|( name, interface )| {
let interface_ident = format!( "{}/{}", binding.0.package_name, name );
interface.add_to_linker_async( linker, &binding.0.package_name, &interface_ident, name, binding )
})
}
pub async fn dispatch_async(
&self,
interface_name: &str,
function_name: &str,
args: &[wasmtime::component::Val],
) -> Result<DispatchResults<PluginId, Plugins, PluginInstanceAsync<Ctx>>, crate::DispatchError>
where
PluginId: Into<Val>,
DispatchResults<PluginId, Plugins, PluginInstanceAsync<Ctx>>: Send,
{
let interface = self.0.interfaces.get( interface_name )
.ok_or_else(|| crate::DispatchError::InvalidInterfacePath( format!( "{}/{}", self.0.package_name, interface_name )))?;
let function = interface.function( function_name )
.ok_or_else(|| crate::DispatchError::InvalidFunction( function_name.to_string() ))?;
let package_name = self.0.package_name.clone();
let interface_name = interface_name.to_string();
let function_name = function_name.to_string();
let function = function.clone();
let args = args.to_vec();
Ok( self.0.plugins.map_async(| _, plugin | {
let package_name = package_name.clone();
let interface_name = interface_name.clone();
let function_name = function_name.clone();
let function = function.clone();
let args = args.clone();
async move {
plugin.lock().await.dispatch_async(
&package_name,
&interface_name,
&function_name,
&function,
&args,
).await
}
}).await )
}
}
#[derive( Debug )]
pub enum BindingAny<PluginId, Ctx, Instance = PluginInstanceSync<Ctx>>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
{
ExactlyOne( Binding<PluginId, Ctx, ExactlyOne<PluginId, Instance>, Instance> ),
AtMostOne( Binding<PluginId, Ctx, AtMostOne<PluginId, Instance>, Instance> ),
AtLeastOne( Binding<PluginId, Ctx, AtLeastOne<PluginId, Instance>, Instance> ),
Any( Binding<PluginId, Ctx, Any<PluginId, Instance>, Instance> ),
}
impl<PluginId, Ctx> BindingAny<PluginId, Ctx, PluginInstanceSync<Ctx>>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
Ctx: PluginContext + 'static,
{
pub(crate) fn add_to_linker( &self, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error> {
match self {
Self::ExactlyOne( binding ) => Binding::add_to_linker( binding, linker ),
Self::AtMostOne( binding ) => Binding::add_to_linker( binding, linker ),
Self::AtLeastOne( binding ) => Binding::add_to_linker( binding, linker ),
Self::Any( binding ) => Binding::add_to_linker( binding, linker ),
}
}
}
impl<PluginId, Ctx> BindingAny<PluginId, Ctx, PluginInstanceAsync<Ctx>>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
Ctx: PluginContext + 'static,
{
pub(crate) fn add_to_linker_async( &self, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error> {
match self {
Self::ExactlyOne( binding ) => Binding::add_to_linker_async( binding, linker ),
Self::AtMostOne( binding ) => Binding::add_to_linker_async( binding, linker ),
Self::AtLeastOne( binding ) => Binding::add_to_linker_async( binding, linker ),
Self::Any( binding ) => Binding::add_to_linker_async( binding, linker ),
}
}
}
impl<PluginId, Ctx, Instance> From<Binding<PluginId, Ctx, ExactlyOne<PluginId, Instance>, Instance>> for BindingAny<PluginId, Ctx, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
{
fn from( binding: Binding<PluginId, Ctx, ExactlyOne<PluginId, Instance>, Instance> ) -> Self {
Self::ExactlyOne( binding )
}
}
impl<PluginId, Ctx, Instance> From<Binding<PluginId, Ctx, AtMostOne<PluginId, Instance>, Instance>> for BindingAny<PluginId, Ctx, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
{
fn from( binding: Binding<PluginId, Ctx, AtMostOne<PluginId, Instance>, Instance> ) -> Self {
Self::AtMostOne( binding )
}
}
impl<PluginId, Ctx, Instance> From<Binding<PluginId, Ctx, AtLeastOne<PluginId, Instance>, Instance>> for BindingAny<PluginId, Ctx, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
{
fn from( binding: Binding<PluginId, Ctx, AtLeastOne<PluginId, Instance>, Instance> ) -> Self {
Self::AtLeastOne( binding )
}
}
impl<PluginId, Ctx, Instance> From<Binding<PluginId, Ctx, Any<PluginId, Instance>, Instance>> for BindingAny<PluginId, Ctx, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
{
fn from( binding: Binding<PluginId, Ctx, Any<PluginId, Instance>, Instance> ) -> Self {
Self::Any( binding )
}
}
impl<PluginId, Ctx, Plugins, Instance> Binding<PluginId, Ctx, Plugins, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
Plugins: Cardinality<PluginId, Instance>,
PluginSockets<PluginId, Plugins, Instance>: Send + Sync,
BindingAny<PluginId, Ctx, Instance>: From<Binding<PluginId, Ctx, Plugins, Instance>>,
{
pub fn into_any( self ) -> BindingAny<PluginId, Ctx, Instance> {
self.into()
}
}
impl<PluginId, Ctx, Instance> Clone for BindingAny<PluginId, Ctx, Instance>
where
PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
Ctx: PluginContext + 'static,
Instance: Send + 'static,
{
fn clone( &self ) -> Self {
match self {
Self::ExactlyOne( binding ) => Self::ExactlyOne( binding.clone() ),
Self::AtMostOne( binding ) => Self::AtMostOne( binding.clone() ),
Self::AtLeastOne( binding ) => Self::AtLeastOne( binding.clone() ),
Self::Any( binding ) => Self::Any( binding.clone() ),
}
}
}