1use std::sync::Arc ;
8use std::collections::HashMap ;
9use futures::lock::Mutex ;
10use wasmtime::component::{ Linker, Val };
11
12use crate::{ Interface, PluginContext };
13use crate::cardinality::{ Any, AtLeastOne, AtMostOne, Cardinality, ExactlyOne };
14use crate::plugin_instance::{ PluginInstanceAsync, PluginInstanceSync };
15
16
17
18type PluginSockets<PluginId, Plugins, Instance> =
19 <Plugins as Cardinality<PluginId, Instance>>::Rebind<Arc<Mutex<Instance>>> ;
20
21type DispatchResults<PluginId, Plugins, Instance> =
22 <PluginSockets<PluginId, Plugins, Instance> as Cardinality<PluginId, Arc<Mutex<Instance>>>>::Rebind<
23 Result<wasmtime::component::Val, crate::DispatchError>
24 >;
25
26type DispatchVals<PluginId, Plugins, Instance> =
27 <PluginSockets<PluginId, Plugins, Instance> as Cardinality<PluginId, Arc<Mutex<Instance>>>>::Rebind<
28 wasmtime::component::Val
29 >;
30
31struct BindingData<PluginId, Plugins, Instance>
32where
33 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
34 Instance: Send + 'static,
35 Plugins: Cardinality<PluginId, Instance>,
36 PluginSockets<PluginId, Plugins, Instance>: Send + Sync,
37{
38 package_name: String,
39 interfaces: HashMap<String, Interface>,
40 plugins: PluginSockets<PluginId, Plugins, Instance>,
41}
42
43pub struct Binding<PluginId, Ctx, Plugins = ExactlyOne<PluginId, PluginInstanceSync<Ctx>>, Instance = PluginInstanceSync<Ctx>>(
90 Arc<BindingData<PluginId, Plugins, Instance>>,
91 std::marker::PhantomData<fn() -> Ctx>,
92)
93where
94 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
95 Ctx: PluginContext + 'static,
96 Instance: Send + 'static,
97 Plugins: Cardinality<PluginId, Instance> + 'static,
98 PluginSockets<PluginId, Plugins, Instance>: Send + Sync;
99
100impl<PluginId, Ctx, Plugins, Instance> Clone for Binding<PluginId, Ctx, Plugins, Instance>
101where
102 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
103 Ctx: PluginContext + 'static,
104 Instance: Send + 'static,
105 Plugins: Cardinality<PluginId, Instance> + 'static,
106 PluginSockets<PluginId, Plugins, Instance>: Send + Sync,
107{
108 fn clone( &self ) -> Self {
111 Self( Arc::clone( &self.0 ), std::marker::PhantomData )
112 }
113}
114
115impl<PluginId, Ctx, Plugins, Instance> std::fmt::Debug for Binding<PluginId, Ctx, Plugins, Instance>
116where
117 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + std::fmt::Debug + 'static,
118 Ctx: PluginContext + std::fmt::Debug + 'static,
119 Instance: Send + 'static,
120 Plugins: Cardinality<PluginId, Instance> + 'static,
121 PluginSockets<PluginId, Plugins, Instance>: Send + Sync + std::fmt::Debug,
122{
123 fn fmt( &self, f: &mut std::fmt::Formatter<'_> ) -> std::fmt::Result {
124 f.debug_struct( "Binding" )
125 .field( "package_name", &self.0.package_name )
126 .field( "interfaces", &self.0.interfaces )
127 .field( "plugins", &self.0.plugins )
128 .finish()
129 }
130}
131
132impl<PluginId, Ctx, Plugins, Instance> Binding<PluginId, Ctx, Plugins, Instance>
133where
134 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
135 Ctx: PluginContext + 'static,
136 Instance: Send + 'static,
137 Plugins: Cardinality<PluginId, Instance> + 'static,
138 PluginSockets<PluginId, Plugins, Instance>: Cardinality<PluginId, Arc<Mutex<Instance>>> + Send + Sync,
139{
140
141 pub fn new(
143 package_name: impl Into<String>,
144 interfaces: HashMap<String, Interface>,
145 plugins: Plugins
146 ) -> Self {
147 Self( Arc::new( BindingData {
148 package_name: package_name.into(),
149 interfaces,
150 plugins: plugins.map_mut(| plugin | Arc::new( Mutex::new( plugin ))),
151 }), std::marker::PhantomData )
152 }
153
154 pub(crate) fn plugins( &self ) -> &PluginSockets<PluginId, Plugins, Instance> {
155 &self.0.plugins
156 }
157}
158
159impl<PluginId, Ctx, Plugins> Binding<PluginId, Ctx, Plugins, PluginInstanceSync<Ctx>>
160where
161 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
162 Ctx: PluginContext + 'static,
163 Plugins: Cardinality<PluginId, PluginInstanceSync<Ctx>> + 'static,
164 PluginSockets<PluginId, Plugins, PluginInstanceSync<Ctx>>: Cardinality<PluginId, Arc<Mutex<PluginInstanceSync<Ctx>>>> + Send + Sync,
165{
166
167 pub(crate) fn add_to_linker( binding: &Binding<PluginId, Ctx, Plugins>, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error>
168 where
169 PluginId: Into<Val>,
170 DispatchVals<PluginId, Plugins, PluginInstanceSync<Ctx>>: Into<Val>,
171 {
172 binding.0.interfaces.iter().try_for_each(|( name, interface )| {
173 let interface_ident = format!( "{}/{}", binding.0.package_name, name );
174 interface.add_to_linker( linker, &binding.0.package_name, &interface_ident, name, binding )
175 })
176 }
177
178 pub fn dispatch(
196 &self,
197 interface_name: &str,
198 function_name: &str,
199 args: &[wasmtime::component::Val],
200 ) -> Result<DispatchResults<PluginId, Plugins, PluginInstanceSync<Ctx>>, crate::DispatchError> {
201
202 let interface = self.0.interfaces.get( interface_name )
203 .ok_or_else(|| crate::DispatchError::InvalidInterfacePath( format!( "{}/{}", self.0.package_name, interface_name )))?;
204
205 let function = interface.function( function_name )
206 .ok_or_else(|| crate::DispatchError::InvalidFunction( function_name.to_string() ))?;
207
208 Ok( self.0.plugins.map(| _, plugin | plugin
209 .try_lock().ok_or( crate::DispatchError::LockRejected )
210 .and_then(| mut lock | lock.dispatch(
211 &self.0.package_name,
212 interface_name,
213 function_name,
214 function,
215 args,
216 ))
217 ))
218
219 }
220
221
222}
223
224impl<PluginId, Ctx, Plugins> Binding<PluginId, Ctx, Plugins, PluginInstanceAsync<Ctx>>
225where
226 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
227 Ctx: PluginContext + 'static,
228 Plugins: Cardinality<PluginId, PluginInstanceAsync<Ctx>> + 'static,
229 PluginSockets<PluginId, Plugins, PluginInstanceAsync<Ctx>>: Cardinality<PluginId, Arc<Mutex<PluginInstanceAsync<Ctx>>>> + Send + Sync,
230{
231 pub(crate) fn add_to_linker_async( binding: &Self, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error>
232 where
233 PluginId: Into<Val>,
234 DispatchVals<PluginId, Plugins, PluginInstanceAsync<Ctx>>: Into<Val> + Send,
235 {
236 binding.0.interfaces.iter().try_for_each(|( name, interface )| {
237 let interface_ident = format!( "{}/{}", binding.0.package_name, name );
238 interface.add_to_linker_async( linker, &binding.0.package_name, &interface_ident, name, binding )
239 })
240 }
241
242 pub async fn dispatch_async(
285 &self,
286 interface_name: &str,
287 function_name: &str,
288 args: &[wasmtime::component::Val],
289 ) -> Result<DispatchResults<PluginId, Plugins, PluginInstanceAsync<Ctx>>, crate::DispatchError>
290 where
291 PluginId: Into<Val>,
292 DispatchResults<PluginId, Plugins, PluginInstanceAsync<Ctx>>: Send,
293 {
294 let interface = self.0.interfaces.get( interface_name )
295 .ok_or_else(|| crate::DispatchError::InvalidInterfacePath( format!( "{}/{}", self.0.package_name, interface_name )))?;
296 let function = interface.function( function_name )
297 .ok_or_else(|| crate::DispatchError::InvalidFunction( function_name.to_string() ))?;
298 let package_name = self.0.package_name.clone();
299 let interface_name = interface_name.to_string();
300 let function_name = function_name.to_string();
301 let function = function.clone();
302 let args = args.to_vec();
303
304 Ok( self.0.plugins.map_async(| _, plugin | {
305 let package_name = package_name.clone();
306 let interface_name = interface_name.clone();
307 let function_name = function_name.clone();
308 let function = function.clone();
309 let args = args.clone();
310 async move {
311 plugin.lock().await.dispatch_async(
312 &package_name,
313 &interface_name,
314 &function_name,
315 &function,
316 &args,
317 ).await
318 }
319 }).await )
320 }
321
322}
323
324#[derive( Debug )]
328pub enum BindingAny<PluginId, Ctx, Instance = PluginInstanceSync<Ctx>>
329where
330 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
331 Ctx: PluginContext + 'static,
332 Instance: Send + 'static,
333{
334 ExactlyOne( Binding<PluginId, Ctx, ExactlyOne<PluginId, Instance>, Instance> ),
336 AtMostOne( Binding<PluginId, Ctx, AtMostOne<PluginId, Instance>, Instance> ),
338 AtLeastOne( Binding<PluginId, Ctx, AtLeastOne<PluginId, Instance>, Instance> ),
340 Any( Binding<PluginId, Ctx, Any<PluginId, Instance>, Instance> ),
342}
343
344impl<PluginId, Ctx> BindingAny<PluginId, Ctx, PluginInstanceSync<Ctx>>
345where
346 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
347 Ctx: PluginContext + 'static,
348{
349 pub(crate) fn add_to_linker( &self, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error> {
350 match self {
351 Self::ExactlyOne( binding ) => Binding::add_to_linker( binding, linker ),
352 Self::AtMostOne( binding ) => Binding::add_to_linker( binding, linker ),
353 Self::AtLeastOne( binding ) => Binding::add_to_linker( binding, linker ),
354 Self::Any( binding ) => Binding::add_to_linker( binding, linker ),
355 }
356 }
357
358}
359
360impl<PluginId, Ctx> BindingAny<PluginId, Ctx, PluginInstanceAsync<Ctx>>
361where
362 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
363 Ctx: PluginContext + 'static,
364{
365 pub(crate) fn add_to_linker_async( &self, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error> {
366 match self {
367 Self::ExactlyOne( binding ) => Binding::add_to_linker_async( binding, linker ),
368 Self::AtMostOne( binding ) => Binding::add_to_linker_async( binding, linker ),
369 Self::AtLeastOne( binding ) => Binding::add_to_linker_async( binding, linker ),
370 Self::Any( binding ) => Binding::add_to_linker_async( binding, linker ),
371 }
372 }
373}
374
375impl<PluginId, Ctx, Instance> From<Binding<PluginId, Ctx, ExactlyOne<PluginId, Instance>, Instance>> for BindingAny<PluginId, Ctx, Instance>
376where
377 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
378 Ctx: PluginContext + 'static,
379 Instance: Send + 'static,
380{
381 fn from( binding: Binding<PluginId, Ctx, ExactlyOne<PluginId, Instance>, Instance> ) -> Self {
382 Self::ExactlyOne( binding )
383 }
384}
385
386impl<PluginId, Ctx, Instance> From<Binding<PluginId, Ctx, AtMostOne<PluginId, Instance>, Instance>> for BindingAny<PluginId, Ctx, Instance>
387where
388 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
389 Ctx: PluginContext + 'static,
390 Instance: Send + 'static,
391{
392 fn from( binding: Binding<PluginId, Ctx, AtMostOne<PluginId, Instance>, Instance> ) -> Self {
393 Self::AtMostOne( binding )
394 }
395}
396
397impl<PluginId, Ctx, Instance> From<Binding<PluginId, Ctx, AtLeastOne<PluginId, Instance>, Instance>> for BindingAny<PluginId, Ctx, Instance>
398where
399 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
400 Ctx: PluginContext + 'static,
401 Instance: Send + 'static,
402{
403 fn from( binding: Binding<PluginId, Ctx, AtLeastOne<PluginId, Instance>, Instance> ) -> Self {
404 Self::AtLeastOne( binding )
405 }
406}
407
408impl<PluginId, Ctx, Instance> From<Binding<PluginId, Ctx, Any<PluginId, Instance>, Instance>> for BindingAny<PluginId, Ctx, Instance>
409where
410 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
411 Ctx: PluginContext + 'static,
412 Instance: Send + 'static,
413{
414 fn from( binding: Binding<PluginId, Ctx, Any<PluginId, Instance>, Instance> ) -> Self {
415 Self::Any( binding )
416 }
417}
418
419impl<PluginId, Ctx, Plugins, Instance> Binding<PluginId, Ctx, Plugins, Instance>
420where
421 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
422 Ctx: PluginContext + 'static,
423 Instance: Send + 'static,
424 Plugins: Cardinality<PluginId, Instance>,
425 PluginSockets<PluginId, Plugins, Instance>: Send + Sync,
426 BindingAny<PluginId, Ctx, Instance>: From<Binding<PluginId, Ctx, Plugins, Instance>>,
427{
428 pub fn into_any( self ) -> BindingAny<PluginId, Ctx, Instance> {
430 self.into()
431 }
432}
433
434impl<PluginId, Ctx, Instance> Clone for BindingAny<PluginId, Ctx, Instance>
435where
436 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
437 Ctx: PluginContext + 'static,
438 Instance: Send + 'static,
439{
440 fn clone( &self ) -> Self {
443 match self {
444 Self::ExactlyOne( binding ) => Self::ExactlyOne( binding.clone() ),
445 Self::AtMostOne( binding ) => Self::AtMostOne( binding.clone() ),
446 Self::AtLeastOne( binding ) => Self::AtLeastOne( binding.clone() ),
447 Self::Any( binding ) => Self::Any( binding.clone() ),
448 }
449 }
450}