1use std::sync::Arc ;
2use std::collections::{ HashMap, HashSet };
3use futures::lock::Mutex ;
4use wasmtime::component::{ Linker, ResourceType, Val };
5
6use crate::{ Binding, PluginContext, PluginInstanceAsync, PluginInstanceSync };
7use crate::cardinality::Cardinality ;
8use crate::linker::{
9 dispatch_all,
10 dispatch_all_async,
11 dispatch_all_async_blocking,
12 dispatch_method,
13 dispatch_method_async,
14 dispatch_method_async_blocking,
15};
16use crate::resource_wrapper::ResourceWrapper ;
17
18#[derive( Debug, Clone, Default )]
44pub struct Interface {
45 functions: HashMap<String, Function>,
47 resources: HashSet<String>,
49}
50
51impl Interface {
52 pub fn new(
54 functions: HashMap<String, Function>,
55 resources: HashSet<String>,
56 ) -> Self {
57 Self { functions, resources }
58 }
59
60 #[inline]
61 pub(crate) fn function( &self, name: &str ) -> Option<&Function> {
62 self.functions.get( name )
63 }
64
65 #[inline]
66 pub(crate) fn add_to_linker<PluginId, Ctx, Plugins>(
67 &self,
68 linker: &mut Linker<Ctx>,
69 package_name: &str,
70 interface_ident: &str,
71 interface_name: &str,
72 binding: &Binding<PluginId, Ctx, Plugins, PluginInstanceSync<Ctx>>,
73 ) -> Result<(), wasmtime::Error>
74 where
75 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
76 Ctx: PluginContext,
77 Plugins: Cardinality<PluginId, PluginInstanceSync<Ctx>> + 'static,
78 <Plugins as Cardinality<PluginId, PluginInstanceSync<Ctx>>>::Rebind<Arc<Mutex<PluginInstanceSync<Ctx>>>>: Send + Sync,
79 <Plugins as Cardinality<PluginId, PluginInstanceSync<Ctx>>>::Rebind<Arc<Mutex<PluginInstanceSync<Ctx>>>>: Cardinality<PluginId, Arc<Mutex<PluginInstanceSync<Ctx>>>>,
80 <<Plugins as Cardinality<PluginId, PluginInstanceSync<Ctx>>>::Rebind<Arc<Mutex<PluginInstanceSync<Ctx>>>> as Cardinality<PluginId, Arc<Mutex<PluginInstanceSync<Ctx>>>>>::Rebind<Val>: Into<Val>,
81 {
82 let mut linker_root = linker.root();
83 let mut linker_instance = linker_root.instance( interface_ident )?;
84
85 self.functions.iter().try_for_each(|( name, metadata )| {
86
87 let package_name_clone = package_name.to_string();
88 let interface_name_clone = interface_name.to_string();
89 let binding_clone = binding.clone();
90 let name_clone = name.clone();
91 let metadata_clone = metadata.clone();
92
93 macro_rules! link {( $dispatch: expr ) => {
94 linker_instance.func_new( name, move | ctx, _ty, args, results | Ok(
95 results[0] = $dispatch( &binding_clone, ctx, &package_name_clone, &interface_name_clone, &name_clone, &metadata_clone, args )
96 ))
97 }}
98
99 match metadata.kind() {
100 FunctionKind::Freestanding => link!( dispatch_all ),
101 FunctionKind::Method => link!( dispatch_method ),
102 }
103
104 })?;
105
106 self.resources.iter().try_for_each(| resource | linker_instance
107 .resource( resource.as_str(), ResourceType::host::<Arc<ResourceWrapper<PluginId>>>(), ResourceWrapper::<PluginId>::drop )
108 )?;
109
110 Ok(())
111
112 }
113
114 #[inline]
115 pub(crate) fn add_to_linker_async<PluginId, Ctx, Plugins>(
116 &self,
117 linker: &mut Linker<Ctx>,
118 package_name: &str,
119 interface_ident: &str,
120 interface_name: &str,
121 binding: &Binding<PluginId, Ctx, Plugins, PluginInstanceAsync<Ctx>>,
122 ) -> Result<(), wasmtime::Error>
123 where
124 PluginId: std::hash::Hash + Eq + Clone + Send + Sync + Into<Val> + 'static,
125 Ctx: PluginContext,
126 Plugins: Cardinality<PluginId, PluginInstanceAsync<Ctx>> + 'static,
127 <Plugins as Cardinality<PluginId, PluginInstanceAsync<Ctx>>>::Rebind<Arc<Mutex<PluginInstanceAsync<Ctx>>>>: Send + Sync,
128 <Plugins as Cardinality<PluginId, PluginInstanceAsync<Ctx>>>::Rebind<Arc<Mutex<PluginInstanceAsync<Ctx>>>>: Cardinality<PluginId, Arc<Mutex<PluginInstanceAsync<Ctx>>>>,
129 <<Plugins as Cardinality<PluginId, PluginInstanceAsync<Ctx>>>::Rebind<Arc<Mutex<PluginInstanceAsync<Ctx>>>> as Cardinality<PluginId, Arc<Mutex<PluginInstanceAsync<Ctx>>>>>::Rebind<Val>: Into<Val> + Send,
130 {
131 let mut linker_root = linker.root();
132 let mut linker_instance = linker_root.instance( interface_ident )?;
133
134 self.functions.iter().try_for_each(|( name, metadata )| {
135 let package_name = package_name.to_string();
136 let interface_name = interface_name.to_string();
137 let binding = binding.clone();
138 let function_name = name.clone();
139 let function = metadata.clone();
140
141 macro_rules! link_concurrent {( $dispatch: expr ) => {
142 linker_instance.func_new_concurrent( name, move | ctx, _ty, args, results | {
143 let package_name = package_name.clone();
144 let interface_name = interface_name.clone();
145 let binding = binding.clone();
146 let function_name = function_name.clone();
147 let function = function.clone();
148 Box::pin( async move {
149 results[0] = $dispatch(
150 &binding, ctx, &package_name, &interface_name, &function_name, &function, args,
151 ).await;
152 Ok(())
153 })
154 })
155 }}
156
157 macro_rules! link_blocking {( $dispatch: expr ) => {
158 linker_instance.func_new_async( name, move | ctx, _ty, args, results | {
159 let package_name = package_name.clone();
160 let interface_name = interface_name.clone();
161 let binding = binding.clone();
162 let function_name = function_name.clone();
163 let function = function.clone();
164 Box::new( async move {
165 results[0] = $dispatch(
166 &binding, ctx, &package_name, &interface_name, &function_name, &function, args,
167 ).await;
168 Ok(())
169 })
170 })
171 }}
172
173 match ( metadata.is_async(), metadata.kind() ) {
174 ( true, FunctionKind::Freestanding ) => link_concurrent!( dispatch_all_async ),
175 ( true, FunctionKind::Method ) => link_concurrent!( dispatch_method_async ),
176 ( false, FunctionKind::Freestanding ) => link_blocking!( dispatch_all_async_blocking ),
177 ( false, FunctionKind::Method ) => link_blocking!( dispatch_method_async_blocking ),
178 }
179 })?;
180
181 self.resources.iter().try_for_each(| resource | linker_instance.resource( resource.as_str(), ResourceType::host::<Arc<ResourceWrapper<PluginId>>>(), ResourceWrapper::<PluginId>::drop ))?;
182
183 Ok(())
184 }
185
186}
187
188#[derive( Debug, Clone, Copy, Eq, PartialEq )]
195pub enum FunctionKind {
196 Freestanding,
198 Method,
200}
201
202#[derive( Debug, Clone )]
206pub struct Function {
207 kind: FunctionKind,
209 return_kind: ReturnKind,
211 is_async: bool,
213}
214
215impl Function {
216 pub fn new(
218 kind: FunctionKind,
219 return_kind: ReturnKind,
220 ) -> Self {
221 Self { kind, return_kind, is_async: false }
222 }
223
224 pub fn new_async(
236 kind: FunctionKind,
237 return_kind: ReturnKind,
238 ) -> Self {
239 Self { kind, return_kind, is_async: true }
240 }
241
242 pub fn return_kind( &self ) -> ReturnKind { self.return_kind }
244
245 pub fn kind( &self ) -> FunctionKind { self.kind }
247
248 pub fn is_async( &self ) -> bool { self.is_async }
256
257}
258
259#[derive( Copy, Clone, Eq, PartialEq, Hash, Debug, Default )]
277pub enum ReturnKind {
278 #[default] Void,
280 MayContainResources,
286 AssumeNoResources,
293}
294
295impl std::fmt::Display for ReturnKind {
296 fn fmt( &self, f: &mut std::fmt::Formatter ) -> Result<(), std::fmt::Error> {
297 match self {
298 Self::Void => write!( f, "Function returns no data" ),
299 Self::MayContainResources => write!( f, "Return type may contain resources" ),
300 Self::AssumeNoResources => write!( f, "Function is assumed to not return any resources" ),
301 }
302 }
303}