1#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate alloc;
23
24use alloc::{borrow::Cow, string::String, vec, vec::Vec};
25use core::{iter::Iterator, marker::PhantomData, mem};
26
27#[cfg(not(all(feature = "std", feature = "wasmtime")))]
28#[macro_export]
29macro_rules! if_wasmtime_is_enabled {
30 ($($token:tt)*) => {};
31}
32
33#[cfg(all(feature = "std", feature = "wasmtime"))]
34#[macro_export]
35macro_rules! if_wasmtime_is_enabled {
36 ($($token:tt)*) => {
37 $($token)*
38 }
39}
40
41if_wasmtime_is_enabled! {
42 pub use wasmtime;
44
45 pub use anyhow;
47}
48
49pub type Result<T> = core::result::Result<T, String>;
51
52#[derive(Copy, Clone, PartialEq, Debug, Eq)]
54pub enum ValueType {
55 I32,
57 I64,
59 F32,
61 F64,
63}
64
65impl From<ValueType> for u8 {
66 fn from(val: ValueType) -> u8 {
67 match val {
68 ValueType::I32 => 0,
69 ValueType::I64 => 1,
70 ValueType::F32 => 2,
71 ValueType::F64 => 3,
72 }
73 }
74}
75
76impl TryFrom<u8> for ValueType {
77 type Error = ();
78
79 fn try_from(val: u8) -> core::result::Result<ValueType, ()> {
80 match val {
81 0 => Ok(Self::I32),
82 1 => Ok(Self::I64),
83 2 => Ok(Self::F32),
84 3 => Ok(Self::F64),
85 _ => Err(()),
86 }
87 }
88}
89
90#[derive(PartialEq, Debug, Clone, Copy, codec::Encode, codec::Decode)]
92pub enum Value {
93 I32(i32),
95 I64(i64),
97 F32(u32),
101 F64(u64),
105}
106
107impl Value {
108 pub fn value_type(&self) -> ValueType {
110 match self {
111 Value::I32(_) => ValueType::I32,
112 Value::I64(_) => ValueType::I64,
113 Value::F32(_) => ValueType::F32,
114 Value::F64(_) => ValueType::F64,
115 }
116 }
117
118 pub fn as_i32(&self) -> Option<i32> {
120 match self {
121 Self::I32(val) => Some(*val),
122 _ => None,
123 }
124 }
125}
126
127mod private {
130 pub trait Sealed {}
131
132 impl Sealed for u8 {}
133 impl Sealed for u16 {}
134 impl Sealed for u32 {}
135 impl Sealed for u64 {}
136
137 impl Sealed for i32 {}
138 impl Sealed for i64 {}
139}
140
141pub trait PointerType: Sized + private::Sealed {
145 const SIZE: u32 = mem::size_of::<Self>() as u32;
147}
148
149impl PointerType for u8 {}
150impl PointerType for u16 {}
151impl PointerType for u32 {}
152impl PointerType for u64 {}
153
154#[derive(Debug, PartialEq, Eq)]
156pub struct Pointer<T> {
157 ptr: u32,
158 _marker: PhantomData<T>,
159}
160
161impl<T> Copy for Pointer<T> {}
162impl<T> Clone for Pointer<T> {
163 fn clone(&self) -> Self {
164 Pointer { ptr: self.ptr, _marker: PhantomData }
165 }
166}
167
168impl<T: PointerType> Pointer<T> {
169 pub fn new(ptr: u32) -> Self {
171 Self { ptr, _marker: Default::default() }
172 }
173
174 pub fn offset(self, offset: u32) -> Option<Self> {
181 offset
182 .checked_mul(T::SIZE)
183 .and_then(|o| self.ptr.checked_add(o))
184 .map(|ptr| Self { ptr, _marker: Default::default() })
185 }
186
187 pub fn null() -> Self {
189 Self::new(0)
190 }
191
192 pub fn cast<R: PointerType>(self) -> Pointer<R> {
194 Pointer::new(self.ptr)
195 }
196}
197
198impl<T: PointerType> From<u32> for Pointer<T> {
199 fn from(ptr: u32) -> Self {
200 Pointer::new(ptr)
201 }
202}
203
204impl<T: PointerType> From<Pointer<T>> for u32 {
205 fn from(ptr: Pointer<T>) -> Self {
206 ptr.ptr
207 }
208}
209
210impl<T: PointerType> From<Pointer<T>> for u64 {
211 fn from(ptr: Pointer<T>) -> Self {
212 u64::from(ptr.ptr)
213 }
214}
215
216impl<T: PointerType> From<Pointer<T>> for usize {
217 fn from(ptr: Pointer<T>) -> Self {
218 ptr.ptr as _
219 }
220}
221
222impl<T: PointerType> IntoValue for Pointer<T> {
223 const VALUE_TYPE: ValueType = ValueType::I32;
224 fn into_value(self) -> Value {
225 Value::I32(self.ptr as _)
226 }
227}
228
229impl<T: PointerType> TryFromValue for Pointer<T> {
230 fn try_from_value(val: Value) -> Option<Self> {
231 match val {
232 Value::I32(val) => Some(Self::new(val as _)),
233 _ => None,
234 }
235 }
236}
237
238pub type WordSize = u32;
240
241#[derive(Eq, PartialEq, Debug, Clone)]
243pub struct Signature {
244 pub args: Cow<'static, [ValueType]>,
246 pub return_value: Option<ValueType>,
248}
249
250impl Signature {
251 pub fn new<T: Into<Cow<'static, [ValueType]>>>(
253 args: T,
254 return_value: Option<ValueType>,
255 ) -> Self {
256 Self { args: args.into(), return_value }
257 }
258
259 pub fn new_with_args<T: Into<Cow<'static, [ValueType]>>>(args: T) -> Self {
261 Self { args: args.into(), return_value: None }
262 }
263}
264
265#[cfg(feature = "std")]
267pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {}
268#[cfg(feature = "std")]
269impl<T: std::panic::RefUnwindSafe> MaybeRefUnwindSafe for T {}
270
271#[cfg(not(feature = "std"))]
273pub trait MaybeRefUnwindSafe {}
274#[cfg(not(feature = "std"))]
275impl<T> MaybeRefUnwindSafe for T {}
276
277pub trait Function: MaybeRefUnwindSafe + Send + Sync {
279 fn name(&self) -> &str;
281 fn signature(&self) -> Signature;
283 fn execute(
285 &self,
286 context: &mut dyn FunctionContext,
287 args: &mut dyn Iterator<Item = Value>,
288 ) -> Result<Option<Value>>;
289}
290
291impl PartialEq for dyn Function {
292 fn eq(&self, other: &Self) -> bool {
293 other.name() == self.name() && other.signature() == self.signature()
294 }
295}
296
297pub trait FunctionContext {
299 fn read_memory(&self, address: Pointer<u8>, size: WordSize) -> Result<Vec<u8>> {
301 let mut vec = vec![0; size as usize];
302 self.read_memory_into(address, &mut vec)?;
303 Ok(vec)
304 }
305 fn read_memory_into(&self, address: Pointer<u8>, dest: &mut [u8]) -> Result<()>;
307 fn write_memory(&mut self, address: Pointer<u8>, data: &[u8]) -> Result<()>;
309 fn allocate_memory(&mut self, size: WordSize) -> Result<Pointer<u8>>;
311 fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> Result<()>;
313 fn register_panic_error_message(&mut self, message: &str);
335}
336
337if_wasmtime_is_enabled! {
338 pub trait HostFunctionRegistry {
345 type State;
346 type Error;
347 type FunctionContext: FunctionContext;
348
349 fn with_function_context<R>(
352 caller: wasmtime::Caller<Self::State>,
353 callback: impl FnOnce(&mut dyn FunctionContext) -> R,
354 ) -> R;
355
356 fn register_static<Params, Results>(
361 &mut self,
362 fn_name: &str,
363 func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
364 ) -> core::result::Result<(), Self::Error>;
365 }
366}
367
368pub trait HostFunctions: 'static + Send + Sync {
370 fn host_functions() -> Vec<&'static dyn Function>;
372
373 if_wasmtime_is_enabled! {
374 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
376 where
377 T: HostFunctionRegistry;
378 }
379}
380
381#[impl_trait_for_tuples::impl_for_tuples(30)]
382impl HostFunctions for Tuple {
383 fn host_functions() -> Vec<&'static dyn Function> {
384 let mut host_functions = Vec::new();
385
386 for_tuples!( #( host_functions.extend(Tuple::host_functions()); )* );
387
388 host_functions
389 }
390
391 #[cfg(all(feature = "std", feature = "wasmtime"))]
392 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
393 where
394 T: HostFunctionRegistry,
395 {
396 for_tuples!(
397 #( Tuple::register_static(registry)?; )*
398 );
399
400 Ok(())
401 }
402}
403
404pub struct ExtendedHostFunctions<Base, Overlay> {
407 phantom: PhantomData<(Base, Overlay)>,
408}
409
410impl<Base, Overlay> HostFunctions for ExtendedHostFunctions<Base, Overlay>
411where
412 Base: HostFunctions,
413 Overlay: HostFunctions,
414{
415 fn host_functions() -> Vec<&'static dyn Function> {
416 let mut base = Base::host_functions();
417 let overlay = Overlay::host_functions();
418 base.retain(|host_fn| {
419 !overlay.iter().any(|ext_host_fn| host_fn.name() == ext_host_fn.name())
420 });
421 base.extend(overlay);
422 base
423 }
424
425 if_wasmtime_is_enabled! {
426 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
427 where
428 T: HostFunctionRegistry,
429 {
430 struct Proxy<'a, T> {
431 registry: &'a mut T,
432 seen_overlay: std::collections::HashSet<String>,
433 seen_base: std::collections::HashSet<String>,
434 overlay_registered: bool,
435 }
436
437 impl<'a, T> HostFunctionRegistry for Proxy<'a, T>
438 where
439 T: HostFunctionRegistry,
440 {
441 type State = T::State;
442 type Error = T::Error;
443 type FunctionContext = T::FunctionContext;
444
445 fn with_function_context<R>(
446 caller: wasmtime::Caller<Self::State>,
447 callback: impl FnOnce(&mut dyn FunctionContext) -> R,
448 ) -> R {
449 T::with_function_context(caller, callback)
450 }
451
452 fn register_static<Params, Results>(
453 &mut self,
454 fn_name: &str,
455 func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
456 ) -> core::result::Result<(), Self::Error> {
457 if self.overlay_registered {
458 if !self.seen_base.insert(fn_name.to_owned()) {
459 log::warn!(
460 target: "extended_host_functions",
461 "Duplicate base host function: '{}'",
462 fn_name,
463 );
464
465 return Ok(())
467 }
468
469 if self.seen_overlay.contains(fn_name) {
470 log::debug!(
472 target: "extended_host_functions",
473 "Overriding base host function: '{}'",
474 fn_name,
475 );
476
477 return Ok(())
478 }
479 } else if !self.seen_overlay.insert(fn_name.to_owned()) {
480 log::warn!(
481 target: "extended_host_functions",
482 "Duplicate overlay host function: '{}'",
483 fn_name,
484 );
485
486 return Ok(())
488 }
489
490 self.registry.register_static(fn_name, func)
491 }
492 }
493
494 let mut proxy = Proxy {
495 registry,
496 seen_overlay: Default::default(),
497 seen_base: Default::default(),
498 overlay_registered: false,
499 };
500
501 Overlay::register_static(&mut proxy)?;
505 proxy.overlay_registered = true;
506 Base::register_static(&mut proxy)?;
507
508 Ok(())
509 }
510 }
511}
512
513#[cfg(all(feature = "std", feature = "wasmtime"))]
517pub trait WasmTy: wasmtime::WasmTy + private::Sealed {}
518
519#[cfg(not(all(feature = "std", feature = "wasmtime")))]
523pub trait WasmTy: private::Sealed {}
524
525impl WasmTy for i32 {}
526impl WasmTy for u32 {}
527impl WasmTy for i64 {}
528impl WasmTy for u64 {}
529
530pub trait IntoValue {
532 const VALUE_TYPE: ValueType;
534
535 fn into_value(self) -> Value;
537}
538
539pub trait TryFromValue: Sized {
541 fn try_from_value(val: Value) -> Option<Self>;
543}
544
545macro_rules! impl_into_and_from_value {
546 (
547 $(
548 $type:ty, $( < $gen:ident >, )? $value_variant:ident,
549 )*
550 ) => {
551 $(
552 impl $( <$gen> )? IntoValue for $type {
553 const VALUE_TYPE: ValueType = ValueType::$value_variant;
554 fn into_value(self) -> Value { Value::$value_variant(self as _) }
555 }
556
557 impl $( <$gen> )? TryFromValue for $type {
558 fn try_from_value(val: Value) -> Option<Self> {
559 match val {
560 Value::$value_variant(val) => Some(val as _),
561 _ => None,
562 }
563 }
564 }
565 )*
566 }
567}
568
569impl_into_and_from_value! {
570 u8, I32,
571 u16, I32,
572 u32, I32,
573 u64, I64,
574 i8, I32,
575 i16, I32,
576 i32, I32,
577 i64, I64,
578}
579
580#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)]
584pub enum ReturnValue {
585 Unit,
587 Value(Value),
589}
590
591impl From<Value> for ReturnValue {
592 fn from(v: Value) -> ReturnValue {
593 ReturnValue::Value(v)
594 }
595}
596
597impl ReturnValue {
598 pub const ENCODED_MAX_SIZE: usize = 10;
605}
606
607#[cfg(test)]
608mod tests {
609 use super::*;
610 use codec::Encode;
611
612 #[test]
613 fn pointer_offset_works() {
614 let ptr = Pointer::<u32>::null();
615
616 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(40));
617 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(128));
618
619 let ptr = Pointer::<u64>::null();
620
621 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80));
622 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256));
623 }
624
625 #[test]
626 fn return_value_encoded_max_size() {
627 let encoded = ReturnValue::Value(Value::I64(-1)).encode();
628 assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
629 }
630}