1#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate alloc;
23
24use alloc::{borrow::Cow, vec, vec::Vec};
25use core::{iter::Iterator, marker::PhantomData, mem, result};
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
49#[cfg(feature = "std")]
51pub type Result<T> = result::Result<T, String>;
52#[cfg(not(feature = "std"))]
53pub type Result<T> = result::Result<T, &'static str>;
54
55#[derive(Copy, Clone, PartialEq, Debug, Eq)]
57pub enum ValueType {
58 I32,
60 I64,
62 F32,
64 F64,
66}
67
68impl From<ValueType> for u8 {
69 fn from(val: ValueType) -> u8 {
70 match val {
71 ValueType::I32 => 0,
72 ValueType::I64 => 1,
73 ValueType::F32 => 2,
74 ValueType::F64 => 3,
75 }
76 }
77}
78
79impl TryFrom<u8> for ValueType {
80 type Error = ();
81
82 fn try_from(val: u8) -> core::result::Result<ValueType, ()> {
83 match val {
84 0 => Ok(Self::I32),
85 1 => Ok(Self::I64),
86 2 => Ok(Self::F32),
87 3 => Ok(Self::F64),
88 _ => Err(()),
89 }
90 }
91}
92
93#[derive(PartialEq, Debug, Clone, Copy, codec::Encode, codec::Decode)]
95pub enum Value {
96 I32(i32),
98 I64(i64),
100 F32(u32),
104 F64(u64),
108}
109
110impl Value {
111 pub fn value_type(&self) -> ValueType {
113 match self {
114 Value::I32(_) => ValueType::I32,
115 Value::I64(_) => ValueType::I64,
116 Value::F32(_) => ValueType::F32,
117 Value::F64(_) => ValueType::F64,
118 }
119 }
120
121 pub fn as_i32(&self) -> Option<i32> {
123 match self {
124 Self::I32(val) => Some(*val),
125 _ => None,
126 }
127 }
128}
129
130mod private {
133 pub trait Sealed {}
134
135 impl Sealed for u8 {}
136 impl Sealed for u16 {}
137 impl Sealed for u32 {}
138 impl Sealed for u64 {}
139
140 impl Sealed for i32 {}
141 impl Sealed for i64 {}
142}
143
144pub trait PointerType: Sized + private::Sealed {
148 const SIZE: u32 = mem::size_of::<Self>() as u32;
150}
151
152impl PointerType for u8 {}
153impl PointerType for u16 {}
154impl PointerType for u32 {}
155impl PointerType for u64 {}
156
157#[derive(Debug, PartialEq, Eq, Clone, Copy)]
159pub struct Pointer<T: PointerType> {
160 ptr: u32,
161 _marker: PhantomData<T>,
162}
163
164impl<T: PointerType> Pointer<T> {
165 pub fn new(ptr: u32) -> Self {
167 Self { ptr, _marker: Default::default() }
168 }
169
170 pub fn offset(self, offset: u32) -> Option<Self> {
177 offset
178 .checked_mul(T::SIZE)
179 .and_then(|o| self.ptr.checked_add(o))
180 .map(|ptr| Self { ptr, _marker: Default::default() })
181 }
182
183 pub fn null() -> Self {
185 Self::new(0)
186 }
187
188 pub fn cast<R: PointerType>(self) -> Pointer<R> {
190 Pointer::new(self.ptr)
191 }
192}
193
194impl<T: PointerType> From<u32> for Pointer<T> {
195 fn from(ptr: u32) -> Self {
196 Pointer::new(ptr)
197 }
198}
199
200impl<T: PointerType> From<Pointer<T>> for u32 {
201 fn from(ptr: Pointer<T>) -> Self {
202 ptr.ptr
203 }
204}
205
206impl<T: PointerType> From<Pointer<T>> for u64 {
207 fn from(ptr: Pointer<T>) -> Self {
208 u64::from(ptr.ptr)
209 }
210}
211
212impl<T: PointerType> From<Pointer<T>> for usize {
213 fn from(ptr: Pointer<T>) -> Self {
214 ptr.ptr as _
215 }
216}
217
218impl<T: PointerType> IntoValue for Pointer<T> {
219 const VALUE_TYPE: ValueType = ValueType::I32;
220 fn into_value(self) -> Value {
221 Value::I32(self.ptr as _)
222 }
223}
224
225impl<T: PointerType> TryFromValue for Pointer<T> {
226 fn try_from_value(val: Value) -> Option<Self> {
227 match val {
228 Value::I32(val) => Some(Self::new(val as _)),
229 _ => None,
230 }
231 }
232}
233
234pub type WordSize = u32;
236
237#[derive(Eq, PartialEq, Debug, Clone)]
239pub struct Signature {
240 pub args: Cow<'static, [ValueType]>,
242 pub return_value: Option<ValueType>,
244}
245
246impl Signature {
247 pub fn new<T: Into<Cow<'static, [ValueType]>>>(
249 args: T,
250 return_value: Option<ValueType>,
251 ) -> Self {
252 Self { args: args.into(), return_value }
253 }
254
255 pub fn new_with_args<T: Into<Cow<'static, [ValueType]>>>(args: T) -> Self {
257 Self { args: args.into(), return_value: None }
258 }
259}
260
261#[cfg(feature = "std")]
263pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {}
264#[cfg(feature = "std")]
265impl<T: std::panic::RefUnwindSafe> MaybeRefUnwindSafe for T {}
266
267#[cfg(not(feature = "std"))]
269pub trait MaybeRefUnwindSafe {}
270#[cfg(not(feature = "std"))]
271impl<T> MaybeRefUnwindSafe for T {}
272
273pub trait Function: MaybeRefUnwindSafe + Send + Sync {
275 fn name(&self) -> &str;
277 fn signature(&self) -> Signature;
279 fn execute(
281 &self,
282 context: &mut dyn FunctionContext,
283 args: &mut dyn Iterator<Item = Value>,
284 ) -> Result<Option<Value>>;
285}
286
287impl PartialEq for dyn Function {
288 fn eq(&self, other: &Self) -> bool {
289 other.name() == self.name() && other.signature() == self.signature()
290 }
291}
292
293pub trait FunctionContext {
295 fn read_memory(&self, address: Pointer<u8>, size: WordSize) -> Result<Vec<u8>> {
297 let mut vec = vec![0; size as usize];
298 self.read_memory_into(address, &mut vec)?;
299 Ok(vec)
300 }
301 fn read_memory_into(&self, address: Pointer<u8>, dest: &mut [u8]) -> Result<()>;
303 fn write_memory(&mut self, address: Pointer<u8>, data: &[u8]) -> Result<()>;
305 fn allocate_memory(&mut self, size: WordSize) -> Result<Pointer<u8>>;
307 fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> Result<()>;
309 fn register_panic_error_message(&mut self, message: &str);
331}
332
333if_wasmtime_is_enabled! {
334 pub trait HostFunctionRegistry {
341 type State;
342 type Error;
343 type FunctionContext: FunctionContext;
344
345 fn with_function_context<R>(
348 caller: wasmtime::Caller<Self::State>,
349 callback: impl FnOnce(&mut dyn FunctionContext) -> R,
350 ) -> R;
351
352 fn register_static<Params, Results>(
357 &mut self,
358 fn_name: &str,
359 func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
360 ) -> core::result::Result<(), Self::Error>;
361 }
362}
363
364pub trait HostFunctions: 'static + Send + Sync {
366 fn host_functions() -> Vec<&'static dyn Function>;
368
369 if_wasmtime_is_enabled! {
370 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
372 where
373 T: HostFunctionRegistry;
374 }
375}
376
377#[impl_trait_for_tuples::impl_for_tuples(30)]
378impl HostFunctions for Tuple {
379 fn host_functions() -> Vec<&'static dyn Function> {
380 let mut host_functions = Vec::new();
381
382 for_tuples!( #( host_functions.extend(Tuple::host_functions()); )* );
383
384 host_functions
385 }
386
387 #[cfg(all(feature = "std", feature = "wasmtime"))]
388 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
389 where
390 T: HostFunctionRegistry,
391 {
392 for_tuples!(
393 #( Tuple::register_static(registry)?; )*
394 );
395
396 Ok(())
397 }
398}
399
400pub struct ExtendedHostFunctions<Base, Overlay> {
403 phantom: PhantomData<(Base, Overlay)>,
404}
405
406impl<Base, Overlay> HostFunctions for ExtendedHostFunctions<Base, Overlay>
407where
408 Base: HostFunctions,
409 Overlay: HostFunctions,
410{
411 fn host_functions() -> Vec<&'static dyn Function> {
412 let mut base = Base::host_functions();
413 let overlay = Overlay::host_functions();
414 base.retain(|host_fn| {
415 !overlay.iter().any(|ext_host_fn| host_fn.name() == ext_host_fn.name())
416 });
417 base.extend(overlay);
418 base
419 }
420
421 if_wasmtime_is_enabled! {
422 fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
423 where
424 T: HostFunctionRegistry,
425 {
426 struct Proxy<'a, T> {
427 registry: &'a mut T,
428 seen_overlay: std::collections::HashSet<String>,
429 seen_base: std::collections::HashSet<String>,
430 overlay_registered: bool,
431 }
432
433 impl<'a, T> HostFunctionRegistry for Proxy<'a, T>
434 where
435 T: HostFunctionRegistry,
436 {
437 type State = T::State;
438 type Error = T::Error;
439 type FunctionContext = T::FunctionContext;
440
441 fn with_function_context<R>(
442 caller: wasmtime::Caller<Self::State>,
443 callback: impl FnOnce(&mut dyn FunctionContext) -> R,
444 ) -> R {
445 T::with_function_context(caller, callback)
446 }
447
448 fn register_static<Params, Results>(
449 &mut self,
450 fn_name: &str,
451 func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
452 ) -> core::result::Result<(), Self::Error> {
453 if self.overlay_registered {
454 if !self.seen_base.insert(fn_name.to_owned()) {
455 log::warn!(
456 target: "extended_host_functions",
457 "Duplicate base host function: '{}'",
458 fn_name,
459 );
460
461 return Ok(())
463 }
464
465 if self.seen_overlay.contains(fn_name) {
466 log::debug!(
468 target: "extended_host_functions",
469 "Overriding base host function: '{}'",
470 fn_name,
471 );
472
473 return Ok(())
474 }
475 } else if !self.seen_overlay.insert(fn_name.to_owned()) {
476 log::warn!(
477 target: "extended_host_functions",
478 "Duplicate overlay host function: '{}'",
479 fn_name,
480 );
481
482 return Ok(())
484 }
485
486 self.registry.register_static(fn_name, func)
487 }
488 }
489
490 let mut proxy = Proxy {
491 registry,
492 seen_overlay: Default::default(),
493 seen_base: Default::default(),
494 overlay_registered: false,
495 };
496
497 Overlay::register_static(&mut proxy)?;
501 proxy.overlay_registered = true;
502 Base::register_static(&mut proxy)?;
503
504 Ok(())
505 }
506 }
507}
508
509#[cfg(all(feature = "std", feature = "wasmtime"))]
513pub trait WasmTy: wasmtime::WasmTy + private::Sealed {}
514
515#[cfg(not(all(feature = "std", feature = "wasmtime")))]
519pub trait WasmTy: private::Sealed {}
520
521impl WasmTy for i32 {}
522impl WasmTy for u32 {}
523impl WasmTy for i64 {}
524impl WasmTy for u64 {}
525
526pub trait IntoValue {
528 const VALUE_TYPE: ValueType;
530
531 fn into_value(self) -> Value;
533}
534
535pub trait TryFromValue: Sized {
537 fn try_from_value(val: Value) -> Option<Self>;
539}
540
541macro_rules! impl_into_and_from_value {
542 (
543 $(
544 $type:ty, $( < $gen:ident >, )? $value_variant:ident,
545 )*
546 ) => {
547 $(
548 impl $( <$gen> )? IntoValue for $type {
549 const VALUE_TYPE: ValueType = ValueType::$value_variant;
550 fn into_value(self) -> Value { Value::$value_variant(self as _) }
551 }
552
553 impl $( <$gen> )? TryFromValue for $type {
554 fn try_from_value(val: Value) -> Option<Self> {
555 match val {
556 Value::$value_variant(val) => Some(val as _),
557 _ => None,
558 }
559 }
560 }
561 )*
562 }
563}
564
565impl_into_and_from_value! {
566 u8, I32,
567 u16, I32,
568 u32, I32,
569 u64, I64,
570 i8, I32,
571 i16, I32,
572 i32, I32,
573 i64, I64,
574}
575
576#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)]
580pub enum ReturnValue {
581 Unit,
583 Value(Value),
585}
586
587impl From<Value> for ReturnValue {
588 fn from(v: Value) -> ReturnValue {
589 ReturnValue::Value(v)
590 }
591}
592
593impl ReturnValue {
594 pub const ENCODED_MAX_SIZE: usize = 10;
601}
602
603#[cfg(test)]
604mod tests {
605 use super::*;
606 use codec::Encode;
607
608 #[test]
609 fn pointer_offset_works() {
610 let ptr = Pointer::<u32>::null();
611
612 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(40));
613 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(128));
614
615 let ptr = Pointer::<u64>::null();
616
617 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80));
618 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256));
619 }
620
621 #[test]
622 fn return_value_encoded_max_size() {
623 let encoded = ReturnValue::Value(Value::I64(-1)).encode();
624 assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
625 }
626}