1use std::sync::{ Arc, Mutex };
8use std::collections::HashMap ;
9use wasmtime::component::{ Linker, Val };
10
11use crate::{ Interface, PluginContext };
12use crate::cardinality::{ Any, AtLeastOne, AtMostOne, Cardinality, ExactlyOne };
13use crate::plugin_instance::PluginInstance ;
14
15
16
17type PluginSockets<PluginId, Ctx, Plugins> =
18 <Plugins as Cardinality<PluginId, PluginInstance<Ctx>>>::Rebind<Mutex<PluginInstance<Ctx>>> ;
19
20type DispatchResults<PluginId, Ctx, Plugins> =
21 <PluginSockets<PluginId, Ctx, Plugins> as Cardinality<PluginId, Mutex<PluginInstance<Ctx>>>>::Rebind<
22 Result<wasmtime::component::Val, crate::DispatchError>
23 >;
24
25type DispatchVals<PluginId, Ctx, Plugins> =
26 <PluginSockets<PluginId, Ctx, Plugins> as Cardinality<PluginId, Mutex<PluginInstance<Ctx>>>>::Rebind<
27 wasmtime::component::Val
28 >;
29
30struct BindingData<PluginId, Ctx, Plugins>
31where
32 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
33 Ctx: PluginContext + 'static,
34 Plugins: Cardinality<PluginId, PluginInstance<Ctx>>,
35 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
36{
37 package_name: String,
38 interfaces: HashMap<String, Interface>,
39 plugins: PluginSockets<PluginId, Ctx, Plugins>,
40}
41
42pub struct Binding<PluginId, Ctx, Plugins = ExactlyOne<PluginId, PluginInstance<Ctx>>>(Arc<BindingData<PluginId, Ctx, Plugins>>)
85where
86 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
87 Ctx: PluginContext + 'static,
88 Plugins: Cardinality<PluginId, PluginInstance<Ctx>> + 'static,
89 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync;
90
91impl<PluginId, Ctx, Plugins> Clone for Binding<PluginId, Ctx, Plugins>
92where
93 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
94 Ctx: PluginContext + 'static,
95 Plugins: Cardinality<PluginId, PluginInstance<Ctx>> + 'static,
96 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
97{
98 fn clone( &self ) -> Self {
99 Self( Arc::clone( &self.0 ))
100 }
101}
102
103impl<PluginId, Ctx, Plugins> std::fmt::Debug for Binding<PluginId, Ctx, Plugins>
104where
105 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + std::fmt::Debug + 'static,
106 Ctx: PluginContext + std::fmt::Debug + 'static,
107 Plugins: Cardinality<PluginId, PluginInstance<Ctx>> + 'static,
108 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
109 PluginSockets<PluginId, Ctx, Plugins>: std::fmt::Debug,
110{
111 fn fmt( &self, f: &mut std::fmt::Formatter<'_> ) -> std::fmt::Result {
112 f.debug_struct( "Binding" )
113 .field( "package_name", &self.0.package_name )
114 .field( "interfaces", &self.0.interfaces )
115 .field( "plugins", &self.0.plugins )
116 .finish()
117 }
118}
119
120impl<PluginId, Ctx, Plugins> Binding<PluginId, Ctx, Plugins>
121where
122 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
123 Ctx: PluginContext + 'static,
124 Plugins: Cardinality<PluginId, PluginInstance<Ctx>> + 'static,
125 PluginSockets<PluginId, Ctx, Plugins>: Cardinality<PluginId, Mutex<PluginInstance<Ctx>>>,
126 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
127{
128
129 pub fn new(
131 package_name: impl Into<String>,
132 interfaces: HashMap<String, Interface>,
133 plugins: Plugins
134 ) -> Self {
135 Self( Arc::new( BindingData {
136 package_name: package_name.into(),
137 interfaces,
138 plugins: plugins.map_mut( Mutex::new ),
139 }))
140 }
141
142 pub(crate) fn add_to_linker( binding: &Binding<PluginId, Ctx, Plugins>, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error>
143 where
144 PluginId: Into<Val>,
145 DispatchVals<PluginId, Ctx, Plugins>: Into<Val>,
146 {
147 binding.0.interfaces.iter().try_for_each(|( name, interface )| {
148 let interface_ident = format!( "{}/{}", binding.0.package_name, name );
149 interface.add_to_linker( linker, &interface_ident, binding )
150 })
151 }
152
153 pub(crate) fn plugins( &self ) -> &PluginSockets<PluginId, Ctx, Plugins> {
154 &self.0.plugins
155 }
156
157 pub fn dispatch(
175 &self,
176 interface_name: &str,
177 function_name: &str,
178 args: &[wasmtime::component::Val],
179 ) -> Result<DispatchResults<PluginId, Ctx, Plugins>, crate::DispatchError> {
180
181 let interface = self.0.interfaces.get( interface_name )
182 .ok_or_else(|| crate::DispatchError::InvalidInterfacePath( format!( "{}/{}", self.0.package_name, interface_name )))?;
183
184 let function = interface.function( function_name )
185 .ok_or_else(|| crate::DispatchError::InvalidFunction( function_name.to_string() ))?;
186
187 let interface_path = format!( "{}/{}", self.0.package_name, interface_name );
188
189 Ok( self.0.plugins.map(| _, plugin | plugin
190 .lock().map_err(|_| crate::DispatchError::LockRejected )
191 .and_then(| mut lock | lock.dispatch(
192 &interface_path,
193 function_name,
194 function,
195 args,
196 ))
197 ))
198
199 }
200
201}
202
203#[derive( Debug, Clone )]
207pub enum BindingAny<PluginId, Ctx>
208where
209 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
210 Ctx: PluginContext + 'static,
211{
212 ExactlyOne( Binding<PluginId, Ctx, ExactlyOne<PluginId, PluginInstance<Ctx>>> ),
214 AtMostOne( Binding<PluginId, Ctx, AtMostOne<PluginId, PluginInstance<Ctx>>> ),
216 AtLeastOne( Binding<PluginId, Ctx, AtLeastOne<PluginId, PluginInstance<Ctx>>> ),
218 Any( Binding<PluginId, Ctx, Any<PluginId, PluginInstance<Ctx>>> ),
220}
221
222impl<PluginId, Ctx> BindingAny<PluginId, Ctx>
223where
224 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
225 Ctx: PluginContext + 'static,
226{
227 pub(crate) fn add_to_linker( &self, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error> {
228 match self {
229 Self::ExactlyOne( binding ) => Binding::add_to_linker( binding, linker ),
230 Self::AtMostOne( binding ) => Binding::add_to_linker( binding, linker ),
231 Self::AtLeastOne( binding ) => Binding::add_to_linker( binding, linker ),
232 Self::Any( binding ) => Binding::add_to_linker( binding, linker ),
233 }
234 }
235}
236
237impl<PluginId, Ctx> From<Binding<PluginId, Ctx, ExactlyOne<PluginId, PluginInstance<Ctx>>>> for BindingAny<PluginId, Ctx>
238where
239 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
240 Ctx: PluginContext + 'static,
241{
242 fn from( binding: Binding<PluginId, Ctx, ExactlyOne<PluginId, PluginInstance<Ctx>>> ) -> Self {
243 Self::ExactlyOne( binding )
244 }
245}
246
247impl<PluginId, Ctx> From<Binding<PluginId, Ctx, AtMostOne<PluginId, PluginInstance<Ctx>>>> for BindingAny<PluginId, Ctx>
248where
249 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
250 Ctx: PluginContext + 'static,
251{
252 fn from( binding: Binding<PluginId, Ctx, AtMostOne<PluginId, PluginInstance<Ctx>>> ) -> Self {
253 Self::AtMostOne( binding )
254 }
255}
256
257impl<PluginId, Ctx> From<Binding<PluginId, Ctx, AtLeastOne<PluginId, PluginInstance<Ctx>>>> for BindingAny<PluginId, Ctx>
258where
259 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
260 Ctx: PluginContext + 'static,
261{
262 fn from( binding: Binding<PluginId, Ctx, AtLeastOne<PluginId, PluginInstance<Ctx>>> ) -> Self {
263 Self::AtLeastOne( binding )
264 }
265}
266
267impl<PluginId, Ctx> From<Binding<PluginId, Ctx, Any<PluginId, PluginInstance<Ctx>>>> for BindingAny<PluginId, Ctx>
268where
269 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
270 Ctx: PluginContext + 'static,
271{
272 fn from( binding: Binding<PluginId, Ctx, Any<PluginId, PluginInstance<Ctx>>> ) -> Self {
273 Self::Any( binding )
274 }
275}
276
277impl<PluginId, Ctx, Plugins> Binding<PluginId, Ctx, Plugins>
278where
279 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
280 Ctx: PluginContext + 'static,
281 Plugins: Cardinality<PluginId, PluginInstance<Ctx>>,
282 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
283 BindingAny<PluginId, Ctx>: From<Binding<PluginId, Ctx, Plugins>>,
284{
285 pub fn into_any( self ) -> BindingAny<PluginId, Ctx> {
287 self.into()
288 }
289}