as_ffi_bindings/
lib.rs

1//! The current module give a free access to an helper. With the goal of
2//! providing an helper to read and write basic pointers in a WebAssembly
3//! script builded from the [AssemblyScript compiler](https://www.assemblyscript.org).
4//!
5//! Thanks to wasmer and the [AssemblyScript Runtime](https://www.assemblyscript.org/garbage-collection.html#runtime-interface),
6//! we can provide functions like `alloc`, `read` and `write` to interact with
7//! a given webassembly instance.
8//!
9//! # Helpers
10//!
11//! For the moment this crate implement helpers for the ArrayBuffer and for strings.
12//! Historically the ArrayBuffer is less tested than the string. But the both allow
13//! you to interact with a wasmer instance.
14//!
15//! ```ignore
16//! let wasm_bytes = include_bytes!(concat!(
17//! env!("CARGO_MANIFEST_DIR"),
18//! "/tests/runtime_exported.wat"
19//! ));
20//! let store = Store::default();
21//! let module = Module::new(&store, wasm_bytes)?;
22//!
23//! let import_object = imports! {
24//! "env" => {
25//!     "abort" => Function::new_native_with_env(&store, Env::default(), abort),
26//! },
27//! };
28//!
29//! let instance = Instance::new(&module, &import_object)?;
30//! let memory = instance.exports.get_memory("memory").expect("get memory");
31//!
32//! let mut env = Env::default();
33//! env.init(&instance)?;
34//!
35//! let get_string = instance
36//! .exports
37//! .get_native_function::<(), StringPtr>("getString")?;
38//!
39//! let str_ptr = get_string.call()?;
40//! let string = str_ptr.read(memory)?;
41//!
42//! assert_eq!(string, "hello test");
43//!
44//! let str_ptr_2 = StringPtr::alloc(&"hello return".to_string(), &env)?;
45//! let string = str_ptr_2.read(memory)?;
46//! assert_eq!(string, "hello return");
47//! ```
48//!
49//!
50//!
51//! # Unsafe note
52//! This crate has a low-level access to your memory, it's often dangerous to
53//! share memory between programs and you should consider this in your
54//! project.
55mod any_ptr;
56mod buffer_ptr;
57mod env;
58mod string_ptr;
59mod tools;
60
61pub use any_ptr::AnyPtr;
62pub use any_ptr::AnyPtrExported;
63pub use any_ptr::Type;
64pub use buffer_ptr::BufferPtr;
65pub use env::Env;
66pub use string_ptr::StringPtr;
67pub use tools::abort;
68
69use std::fmt;
70use wasmer::Memory;
71
72pub trait Read<T> {
73    /// Read the value contained in the given memory at the current pointer
74    /// offset.
75    ///
76    /// # Return
77    /// A result with an Error if for some reason the binding failed to read
78    /// the offset returned. It can be a cast error for example.
79    ///
80    /// Otherwise, a success with the value red at the point.
81    ///
82    /// # Example
83    /// ```ignore
84    /// let get_string = instance
85    ///     .exports
86    ///     .get_native_function::<(), StringPtr>("getString")?;
87    /// let str_ptr = get_string.call()?;
88    /// let string = str_ptr.read(memory)?;
89    /// ```
90    fn read(&self, memory: &Memory) -> anyhow::Result<T>;
91    /// Read the size as indicated in the [AssemblyScript object header](https://www.assemblyscript.org/memory.html#internals)
92    ///
93    /// # Return
94    /// A result with an Error if for some reason the binding failed to read
95    /// the offset returned. It can be a cast error for example.
96    ///
97    /// Otherwise, a success with the size.
98    ///
99    /// # Example
100    /// ```ignore
101    /// let get_string = instance
102    ///     .exports
103    ///     .get_native_function::<(), StringPtr>("getString")?;
104    /// let str_ptr = get_string.call()?;
105    /// let size: u32 = str_ptr.size(memory)?;
106    /// ```
107    fn size(&self, memory: &Memory) -> anyhow::Result<u32>;
108}
109
110pub trait Write<T> {
111    /// Try to write in the given environment a new value thanks to the
112    /// AssemblyScript runtime.
113    ///
114    /// # Return
115    /// A result with an Error if the given environment don't export the
116    /// [AssemblyScript Runtime](https://www.assemblyscript.org/garbage-collection.html#runtime-interface)
117    /// or if for some reason the binding failed to read the offset returned.
118    ///
119    /// Otherwise, the result return a success containing the new pointer.
120    ///
121    /// # Example
122    /// ```ignore
123    /// let mut env = Env::default();
124    /// env.init(&instance)?;
125    /// let str_ptr = StringPtr::alloc(&"hello return".to_string(), &env)?;
126    /// ```
127    fn alloc(value: &T, env: &Env) -> anyhow::Result<Box<Self>>;
128    /// Try to write in the given environment a value. If the size is
129    /// different, we procede to free the previous string and realloc a new
130    /// pointer.
131    ///
132    /// # Return
133    /// A result with an Error if the given environment don't export the
134    /// [AssemblyScript Runtime](https://www.assemblyscript.org/garbage-collection.html#runtime-interface)
135    /// or if for some reason the binding failed to read the offset returned.
136    ///
137    /// Otherwise, the result return a success containing pointer. This pointer
138    /// can be another if a reallocation occured.
139    ///
140    /// # Example
141    ///
142    /// ```ignore
143    /// let mut env = Env::default();
144    /// env.init(&instance)?;
145    /// let string = str_ptr.write(&"hello return".to_string(), &env)?;
146    /// ```
147    fn write(&mut self, value: &T, env: &Env) -> anyhow::Result<Box<Self>>;
148    /// Unpin the pointer
149    fn free(self, env: &Env) -> anyhow::Result<()>;
150}
151
152#[derive(Debug)]
153pub enum Error {
154    Mem(&'static str),
155}
156
157impl fmt::Display for Error {
158    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159        match self {
160            Error::Mem(err) => write!(f, "{}", err),
161        }
162    }
163}
164
165impl std::error::Error for Error {}