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 {}