uptown_funk/
lib.rs

1pub mod memory;
2pub mod state;
3pub mod types;
4#[cfg(feature = "vm-wasmer")]
5pub mod wasmer;
6
7use std::convert::Into;
8use std::fmt::Debug;
9use std::{
10    cell::{Ref, RefCell, RefMut},
11    rc::Rc,
12};
13
14pub use smallvec::SmallVec;
15pub use uptown_funk_macro::host_functions;
16
17/// Provides access to the instance execution environment.
18pub trait Executor {
19    type Return: Clone;
20
21    /// Execute `Future` f.
22    #[cfg(feature = "async")]
23    fn async_<R, F>(&self, f: F) -> R
24    where
25        F: std::future::Future<Output = R>;
26
27    /// Get mutable access to the instance memory.
28    fn memory(&self) -> memory::Memory;
29}
30
31pub trait HostFunctions: Sized {
32    type Return: Clone + 'static;
33
34    #[cfg(feature = "vm-wasmtime")]
35    fn add_to_linker<E>(self, executor: E, linker: &mut wasmtime::Linker) -> Self::Return
36    where
37        E: Executor + Clone + 'static;
38
39    #[cfg(feature = "vm-wasmer")]
40    fn add_to_wasmer_linker<E>(
41        self,
42        executor: E,
43        linker: &mut wasmer::WasmerLinker,
44        store: &::wasmer::Store,
45    ) -> Self::Return
46    where
47        E: Executor + Clone + 'static;
48}
49
50pub trait StateMarker: Sized {}
51pub trait Convert<To: Sized>: Sized {
52    fn convert(&mut self) -> &mut To;
53}
54
55impl<T: StateMarker> Convert<T> for T {
56    fn convert(&mut self) -> &mut T {
57        self
58    }
59}
60
61impl<'a, T: StateMarker> Convert<T> for RefMut<'a, T> {
62    fn convert(&mut self) -> &mut T {
63        self
64    }
65}
66
67static mut NOSTATE: () = ();
68
69impl<T: StateMarker> Convert<()> for T {
70    fn convert(&mut self) -> &mut () {
71        unsafe { &mut NOSTATE }
72    }
73}
74
75impl<'a, T: StateMarker> Convert<()> for RefMut<'a, T> {
76    fn convert(&mut self) -> &mut () {
77        unsafe { &mut NOSTATE }
78    }
79}
80
81impl Convert<()> for () {
82    fn convert(&mut self) -> &mut () {
83        self
84    }
85}
86
87pub trait FromWasm {
88    type From;
89    type State: Convert<Self::State> + Convert<()>;
90
91    fn from(
92        state: &mut Self::State,
93        executor: &impl Executor,
94        from: Self::From,
95    ) -> Result<Self, Trap>
96    where
97        Self: Sized;
98}
99
100pub trait ToWasm {
101    type To;
102    type State: Convert<Self::State> + Convert<()>;
103
104    fn to(
105        state: &mut Self::State,
106        executor: &impl Executor,
107        host_value: Self,
108    ) -> Result<Self::To, Trap>;
109}
110
111pub struct StateWrapper<S, E: Executor> {
112    state: Rc<RefCell<S>>,
113    env: Rc<E>,
114}
115
116impl<S, E: Executor> StateWrapper<S, E> {
117    pub fn new(state: S, executor: E) -> Self {
118        Self {
119            state: Rc::new(RefCell::new(state)),
120            env: Rc::new(executor),
121        }
122    }
123
124    pub fn borrow_state(&self) -> Ref<S> {
125        self.state.borrow()
126    }
127
128    pub fn borrow_state_mut(&self) -> RefMut<S> {
129        self.state.borrow_mut()
130    }
131
132    pub fn get_state(&self) -> Rc<RefCell<S>> {
133        self.state.clone()
134    }
135
136    pub fn executor(&self) -> &E {
137        &self.env
138    }
139
140    pub fn memory(&self) -> memory::Memory {
141        self.env.memory()
142    }
143
144    pub fn recover_state(self) -> Result<S, ()> {
145        match Rc::try_unwrap(self.state) {
146            Ok(s) => Ok(s.into_inner()),
147            Err(_) => Err(()),
148        }
149    }
150}
151
152// TODO document these
153#[cfg(feature = "vm-wasmer")]
154unsafe impl<S, E: Executor> Send for StateWrapper<S, E> {}
155#[cfg(feature = "vm-wasmer")]
156unsafe impl<S, E: Executor> Sync for StateWrapper<S, E> {}
157
158impl<S, E: Executor> Clone for StateWrapper<S, E> {
159    fn clone(&self) -> Self {
160        Self {
161            state: self.state.clone(),
162            env: self.env.clone(),
163        }
164    }
165}
166
167#[cfg(feature = "vm-wasmer")]
168impl<S, E: Executor> ::wasmer::WasmerEnv for StateWrapper<S, E> {
169    fn init_with_instance(
170        &mut self,
171        _: &::wasmer::Instance,
172    ) -> Result<(), ::wasmer::HostEnvInitError> {
173        Ok(())
174    }
175}
176
177#[cfg_attr(feature = "vm-wasmer", derive(thiserror::Error))]
178#[cfg_attr(feature = "vm-wasmer", error("{message}"))]
179pub struct Trap<D = ()>
180where
181    D: 'static,
182{
183    message: String,
184    data: Option<D>,
185}
186
187impl<D> Debug for Trap<D> {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        Debug::fmt(&self.message, f)
190    }
191}
192
193impl Trap<()> {
194    pub fn new<I: Into<String>>(message: I) -> Self {
195        Self {
196            message: message.into(),
197            data: None,
198        }
199    }
200
201    pub fn with_data<D: 'static>(self, data: D) -> Trap<D> {
202        Trap {
203            message: self.message,
204            data: Some(data),
205        }
206    }
207
208    pub fn try_option<R: Debug>(result: Option<R>) -> Result<R, Trap> {
209        match result {
210            Some(r) => Ok(r),
211            None => Err(Trap::new(
212                "Host function trapped: Memory location not inside wasm guest",
213            )),
214        }
215    }
216
217    pub fn try_result<R: Debug, E: Debug>(result: Result<R, E>) -> Result<R, Trap> {
218        match result {
219            Ok(r) => Ok(r),
220            Err(_) => {
221                let message = format!("Host function trapped: {:?}", result);
222                Err(Trap::new(message))
223            }
224        }
225    }
226}
227
228impl ToWasm for Trap {
229    type To = ();
230    type State = ();
231
232    fn to(_: &mut (), _: &impl Executor, v: Self) -> Result<(), Trap> {
233        Err(v)
234    }
235}
236
237#[cfg(feature = "vm-wasmtime")]
238impl From<Trap> for wasmtime::Trap {
239    fn from(trap: Trap) -> Self {
240        wasmtime::Trap::new(trap.message)
241    }
242}
243
244#[repr(C)]
245pub struct IoVecT {
246    pub ptr: u32,
247    pub len: u32,
248}