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: 'static;
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}