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>>)
86where
87 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
88 Ctx: PluginContext + 'static,
89 Plugins: Cardinality<PluginId, PluginInstance<Ctx>> + 'static,
90 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync;
91
92impl<PluginId, Ctx, Plugins> Clone for Binding<PluginId, Ctx, Plugins>
93where
94 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
95 Ctx: PluginContext + 'static,
96 Plugins: Cardinality<PluginId, PluginInstance<Ctx>> + 'static,
97 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
98{
99 fn clone( &self ) -> Self {
102 Self( Arc::clone( &self.0 ))
103 }
104}
105
106impl<PluginId, Ctx, Plugins> std::fmt::Debug for Binding<PluginId, Ctx, Plugins>
107where
108 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + std::fmt::Debug + 'static,
109 Ctx: PluginContext + std::fmt::Debug + 'static,
110 Plugins: Cardinality<PluginId, PluginInstance<Ctx>> + 'static,
111 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
112 PluginSockets<PluginId, Ctx, Plugins>: std::fmt::Debug,
113{
114 fn fmt( &self, f: &mut std::fmt::Formatter<'_> ) -> std::fmt::Result {
115 f.debug_struct( "Binding" )
116 .field( "package_name", &self.0.package_name )
117 .field( "interfaces", &self.0.interfaces )
118 .field( "plugins", &self.0.plugins )
119 .finish()
120 }
121}
122
123impl<PluginId, Ctx, Plugins> Binding<PluginId, Ctx, Plugins>
124where
125 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
126 Ctx: PluginContext + 'static,
127 Plugins: Cardinality<PluginId, PluginInstance<Ctx>> + 'static,
128 PluginSockets<PluginId, Ctx, Plugins>: Cardinality<PluginId, Mutex<PluginInstance<Ctx>>>,
129 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
130{
131
132 pub fn new(
134 package_name: impl Into<String>,
135 interfaces: HashMap<String, Interface>,
136 plugins: Plugins
137 ) -> Self {
138 Self( Arc::new( BindingData {
139 package_name: package_name.into(),
140 interfaces,
141 plugins: plugins.map_mut( Mutex::new ),
142 }))
143 }
144
145 pub(crate) fn add_to_linker( binding: &Binding<PluginId, Ctx, Plugins>, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error>
146 where
147 PluginId: Into<Val>,
148 DispatchVals<PluginId, Ctx, Plugins>: Into<Val>,
149 {
150 binding.0.interfaces.iter().try_for_each(|( name, interface )| {
151 let interface_ident = format!( "{}/{}", binding.0.package_name, name );
152 interface.add_to_linker( linker, &binding.0.package_name, &interface_ident, name, binding )
153 })
154 }
155
156 pub(crate) fn plugins( &self ) -> &PluginSockets<PluginId, Ctx, Plugins> {
157 &self.0.plugins
158 }
159
160 pub fn dispatch(
178 &self,
179 interface_name: &str,
180 function_name: &str,
181 args: &[wasmtime::component::Val],
182 ) -> Result<DispatchResults<PluginId, Ctx, Plugins>, crate::DispatchError> {
183
184 let interface = self.0.interfaces.get( interface_name )
185 .ok_or_else(|| crate::DispatchError::InvalidInterfacePath( format!( "{}/{}", self.0.package_name, interface_name )))?;
186
187 let function = interface.function( function_name )
188 .ok_or_else(|| crate::DispatchError::InvalidFunction( function_name.to_string() ))?;
189
190 Ok( self.0.plugins.map(| _, plugin | plugin
191 .lock().map_err(|_| crate::DispatchError::LockRejected )
192 .and_then(| mut lock | lock.dispatch(
193 &self.0.package_name,
194 interface_name,
195 function_name,
196 function,
197 args,
198 ))
199 ))
200
201 }
202
203}
204
205#[derive( Debug )]
209pub enum BindingAny<PluginId, Ctx>
210where
211 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
212 Ctx: PluginContext + 'static,
213{
214 ExactlyOne( Binding<PluginId, Ctx, ExactlyOne<PluginId, PluginInstance<Ctx>>> ),
216 AtMostOne( Binding<PluginId, Ctx, AtMostOne<PluginId, PluginInstance<Ctx>>> ),
218 AtLeastOne( Binding<PluginId, Ctx, AtLeastOne<PluginId, PluginInstance<Ctx>>> ),
220 Any( Binding<PluginId, Ctx, Any<PluginId, PluginInstance<Ctx>>> ),
222}
223
224impl<PluginId, Ctx> BindingAny<PluginId, Ctx>
225where
226 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
227 Ctx: PluginContext + 'static,
228{
229 pub(crate) fn add_to_linker( &self, linker: &mut Linker<Ctx> ) -> Result<(), wasmtime::Error> {
230 match self {
231 Self::ExactlyOne( binding ) => Binding::add_to_linker( binding, linker ),
232 Self::AtMostOne( binding ) => Binding::add_to_linker( binding, linker ),
233 Self::AtLeastOne( binding ) => Binding::add_to_linker( binding, linker ),
234 Self::Any( binding ) => Binding::add_to_linker( binding, linker ),
235 }
236 }
237}
238
239impl<PluginId, Ctx> From<Binding<PluginId, Ctx, ExactlyOne<PluginId, PluginInstance<Ctx>>>> for BindingAny<PluginId, Ctx>
240where
241 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
242 Ctx: PluginContext + 'static,
243{
244 fn from( binding: Binding<PluginId, Ctx, ExactlyOne<PluginId, PluginInstance<Ctx>>> ) -> Self {
245 Self::ExactlyOne( binding )
246 }
247}
248
249impl<PluginId, Ctx> From<Binding<PluginId, Ctx, AtMostOne<PluginId, PluginInstance<Ctx>>>> for BindingAny<PluginId, Ctx>
250where
251 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
252 Ctx: PluginContext + 'static,
253{
254 fn from( binding: Binding<PluginId, Ctx, AtMostOne<PluginId, PluginInstance<Ctx>>> ) -> Self {
255 Self::AtMostOne( binding )
256 }
257}
258
259impl<PluginId, Ctx> From<Binding<PluginId, Ctx, AtLeastOne<PluginId, PluginInstance<Ctx>>>> for BindingAny<PluginId, Ctx>
260where
261 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
262 Ctx: PluginContext + 'static,
263{
264 fn from( binding: Binding<PluginId, Ctx, AtLeastOne<PluginId, PluginInstance<Ctx>>> ) -> Self {
265 Self::AtLeastOne( binding )
266 }
267}
268
269impl<PluginId, Ctx> From<Binding<PluginId, Ctx, Any<PluginId, PluginInstance<Ctx>>>> for BindingAny<PluginId, Ctx>
270where
271 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
272 Ctx: PluginContext + 'static,
273{
274 fn from( binding: Binding<PluginId, Ctx, Any<PluginId, PluginInstance<Ctx>>> ) -> Self {
275 Self::Any( binding )
276 }
277}
278
279impl<PluginId, Ctx, Plugins> Binding<PluginId, Ctx, Plugins>
280where
281 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
282 Ctx: PluginContext + 'static,
283 Plugins: Cardinality<PluginId, PluginInstance<Ctx>>,
284 PluginSockets<PluginId, Ctx, Plugins>: Send + Sync,
285 BindingAny<PluginId, Ctx>: From<Binding<PluginId, Ctx, Plugins>>,
286{
287 pub fn into_any( self ) -> BindingAny<PluginId, Ctx> {
289 self.into()
290 }
291}
292
293impl<PluginId, Ctx> Clone for BindingAny<PluginId, Ctx>
294where
295 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
296 Ctx: PluginContext + 'static,
297{
298 fn clone( &self ) -> Self {
301 match self {
302 Self::ExactlyOne( binding ) => Self::ExactlyOne( binding.clone() ),
303 Self::AtMostOne( binding ) => Self::AtMostOne( binding.clone() ),
304 Self::AtLeastOne( binding ) => Self::AtLeastOne( binding.clone() ),
305 Self::Any( binding ) => Self::Any( binding.clone() ),
306 }
307 }
308}