1#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate alloc;
23
24use alloc::{vec, vec::Vec};
25use core::{iter::Iterator, marker::PhantomData, result};
26pub use sp_wasm_interface_common::{
27 self as common, HostPointer, IntoValue, MemoryId, Pointer, PointerType, ReturnValue, Signature,
28 TryFromValue, Value, ValueType, WordSize,
29};
30
31if_wasmtime_is_enabled! {
32 mod host_state;
33 pub use host_state::HostState;
34
35 mod store_data;
36 pub use store_data::StoreData;
37
38 mod memory_wrapper;
39 pub use memory_wrapper::MemoryWrapper;
40
41 pub mod util;
42}
43
44#[cfg(not(all(feature = "std", feature = "wasmtime")))]
45pub struct StoreData;
46
47#[cfg(not(all(feature = "std", feature = "wasmtime")))]
48#[macro_export]
49macro_rules! if_wasmtime_is_enabled {
50 ($($token:tt)*) => {};
51}
52
53#[cfg(all(feature = "std", feature = "wasmtime"))]
54#[macro_export]
55macro_rules! if_wasmtime_is_enabled {
56 ($($token:tt)*) => {
57 $($token)*
58 }
59}
60
61if_wasmtime_is_enabled! {
62 pub use wasmtime;
64
65 pub use anyhow;
67}
68
69#[cfg(feature = "std")]
71pub type Result<T> = result::Result<T, String>;
72#[cfg(not(feature = "std"))]
73pub type Result<T> = result::Result<T, &'static str>;
74
75mod private {
78 pub trait Sealed {}
79
80 impl Sealed for u8 {}
81 impl Sealed for u16 {}
82 impl Sealed for u32 {}
83 impl Sealed for u64 {}
84
85 impl Sealed for i32 {}
86 impl Sealed for i64 {}
87}
88
89#[cfg(feature = "std")]
91pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {}
92#[cfg(feature = "std")]
93impl<T: std::panic::RefUnwindSafe> MaybeRefUnwindSafe for T {}
94
95#[cfg(not(feature = "std"))]
97pub trait MaybeRefUnwindSafe {}
98#[cfg(not(feature = "std"))]
99impl<T> MaybeRefUnwindSafe for T {}
100
101pub trait Function: MaybeRefUnwindSafe + Send + Sync {
103 fn name(&self) -> &str;
105 fn signature(&self) -> Signature;
107 fn execute(
109 &self,
110 context: &mut dyn FunctionContext,
111 args: &mut dyn Iterator<Item = Value>,
112 ) -> Result<Option<Value>>;
113}
114
115impl PartialEq for dyn Function {
116 fn eq(&self, other: &Self) -> bool {
117 other.name() == self.name() && other.signature() == self.signature()
118 }
119}
120
121#[cfg(not(all(feature = "std", feature = "wasmtime")))]
122pub struct Caller<'a, T>(PhantomData<&'a T>);
123
124#[cfg(all(feature = "std", feature = "wasmtime"))]
125pub use wasmtime::Caller;
126
127pub trait FunctionContext {
129 fn read_memory(&self, address: Pointer<u8>, size: WordSize) -> Result<Vec<u8>> {
131 let mut vec = vec![0; size as usize];
132 self.read_memory_into(address, &mut vec)?;
133 Ok(vec)
134 }
135 fn read_memory_into(&self, address: Pointer<u8>, dest: &mut [u8]) -> Result<()>;
137 fn write_memory(&mut self, address: Pointer<u8>, data: &[u8]) -> Result<()>;
139 fn allocate_memory(&mut self, size: WordSize) -> Result<Pointer<u8>>;
141 fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> Result<()>;
143 fn register_panic_error_message(&mut self, message: &str);
165}
166
167if_wasmtime_is_enabled! {
168 pub trait HostFunctionRegistry {
175 type State: 'static;
176 type Error;
177 type FunctionContext: FunctionContext;
178
179 fn with_function_context<R>(
182 caller: wasmtime::Caller<Self::State>,
183 callback: impl FnOnce(&mut dyn FunctionContext) -> R,
184 ) -> R;
185
186 fn register_static<Params, Results>(
191 &mut self,
192 fn_name: &str,
193 func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
194 ) -> core::result::Result<(), Self::Error>;
195 }
196}
197
198pub trait HostFunctions: 'static + Send + Sync {
200 fn host_functions() -> Vec<&'static dyn Function>;
202
203 if_wasmtime_is_enabled! {
204 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
206 where
207 T: HostFunctionRegistry;
208 }
209}
210
211#[impl_trait_for_tuples::impl_for_tuples(30)]
212impl HostFunctions for Tuple {
213 #[allow(clippy::let_and_return)]
214 fn host_functions() -> Vec<&'static dyn Function> {
215 let mut host_functions = Vec::new();
216
217 for_tuples!( #( host_functions.extend(Tuple::host_functions()); )* );
218
219 host_functions
220 }
221
222 #[cfg(all(feature = "std", feature = "wasmtime"))]
223 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
224 where
225 T: HostFunctionRegistry,
226 {
227 for_tuples!(
228 #( Tuple::register_static(registry)?; )*
229 );
230
231 Ok(())
232 }
233}
234
235pub struct ExtendedHostFunctions<Base, Overlay> {
238 phantom: PhantomData<(Base, Overlay)>,
239}
240
241impl<Base, Overlay> HostFunctions for ExtendedHostFunctions<Base, Overlay>
242where
243 Base: HostFunctions,
244 Overlay: HostFunctions,
245{
246 fn host_functions() -> Vec<&'static dyn Function> {
247 let mut base = Base::host_functions();
248 let overlay = Overlay::host_functions();
249 base.retain(|host_fn| {
250 !overlay
251 .iter()
252 .any(|ext_host_fn| host_fn.name() == ext_host_fn.name())
253 });
254 base.extend(overlay);
255 base
256 }
257
258 if_wasmtime_is_enabled! {
259 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
260 where
261 T: HostFunctionRegistry,
262 {
263 struct Proxy<'a, T> {
264 registry: &'a mut T,
265 seen_overlay: std::collections::HashSet<String>,
266 seen_base: std::collections::HashSet<String>,
267 overlay_registered: bool,
268 }
269
270 impl<'a, T> HostFunctionRegistry for Proxy<'a, T>
271 where
272 T: HostFunctionRegistry,
273 {
274 type State = T::State;
275 type Error = T::Error;
276 type FunctionContext = T::FunctionContext;
277
278 fn with_function_context<R>(
279 caller: wasmtime::Caller<Self::State>,
280 callback: impl FnOnce(&mut dyn FunctionContext) -> R,
281 ) -> R {
282 T::with_function_context(caller, callback)
283 }
284
285 fn register_static<Params, Results>(
286 &mut self,
287 fn_name: &str,
288 func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
289 ) -> core::result::Result<(), Self::Error> {
290 if self.overlay_registered {
291 if !self.seen_base.insert(fn_name.to_owned()) {
292 log::warn!(
293 target: "extended_host_functions",
294 "Duplicate base host function: '{}'",
295 fn_name,
296 );
297
298 return Ok(())
300 }
301
302 if self.seen_overlay.contains(fn_name) {
303 log::debug!(
305 target: "extended_host_functions",
306 "Overriding base host function: '{}'",
307 fn_name,
308 );
309
310 return Ok(())
311 }
312 } else if !self.seen_overlay.insert(fn_name.to_owned()) {
313 log::warn!(
314 target: "extended_host_functions",
315 "Duplicate overlay host function: '{}'",
316 fn_name,
317 );
318
319 return Ok(())
321 }
322
323 self.registry.register_static(fn_name, func)
324 }
325 }
326
327 let mut proxy = Proxy {
328 registry,
329 seen_overlay: Default::default(),
330 seen_base: Default::default(),
331 overlay_registered: false,
332 };
333
334 Overlay::register_static(&mut proxy)?;
338 proxy.overlay_registered = true;
339 Base::register_static(&mut proxy)?;
340
341 Ok(())
342 }
343 }
344}
345
346#[cfg(all(feature = "std", feature = "wasmtime"))]
350pub trait WasmTy: wasmtime::WasmTy + private::Sealed {}
351
352#[cfg(not(all(feature = "std", feature = "wasmtime")))]
356pub trait WasmTy: private::Sealed {}
357
358impl WasmTy for i32 {}
359impl WasmTy for u32 {}
360impl WasmTy for i64 {}
361impl WasmTy for u64 {}