as-ffi-bindings 0.2.2

Helpers to read and write memory in AssemblyScript wasm modules
Documentation
///! The current module give a free access to an helper. With the goal of
///! providing an helper to read and write basic pointers in a WebAssembly
///! script builded from the [AssemblyScript compiler](https://www.assemblyscript.org).
///!
///! Thanks to wasmer and the [AssemblyScript Runtime](https://www.assemblyscript.org/garbage-collection.html#runtime-interface),
///! we can provide functions like `alloc`, `read` and `write` to interact with
///! a given webassembly instance.
///!
///! # Helpers
///!
///! For the moment this crate implement helpers for the ArrayBuffer and for strings.
///! Historically the ArrayBuffer is less tested than the string. But the both allow
///! you to interact with a wasmer instance.
///!
///! ```ignore
///! let wasm_bytes = include_bytes!(concat!(
///! env!("CARGO_MANIFEST_DIR"),
///! "/tests/runtime_exported.wat"
///! ));
///! let store = Store::default();
///! let module = Module::new(&store, wasm_bytes)?;
///!
///! let import_object = imports! {
///! "env" => {
///!     "abort" => Function::new_native_with_env(&store, Env::default(), abort),
///! },
///! };
///!
///! let instance = Instance::new(&module, &import_object)?;
///! let memory = instance.exports.get_memory("memory").expect("get memory");
///!
///! let mut env = Env::default();
///! env.init(&instance)?;
///!
///! let get_string = instance
///! .exports
///! .get_native_function::<(), StringPtr>("getString")?;
///!
///! let str_ptr = get_string.call()?;
///! let string = str_ptr.read(memory)?;
///!
///! assert_eq!(string, "hello test");
///!
///! let str_ptr_2 = StringPtr::alloc(&"hello return".to_string(), &env)?;
///! let string = str_ptr_2.read(memory)?;
///! assert_eq!(string, "hello return");
///! ```
///!
///!
///!
///! # Unsafe note
///! This crate has a low-level access to your memory, it's often dangerous to
///! share memory between programs and you should consider this in your
///! project.
mod buffer_ptr;
mod env;
mod string_ptr;
mod tools;

pub use buffer_ptr::BufferPtr;
pub use env::Env;
pub use string_ptr::StringPtr;
pub use tools::abort;

use std::fmt;
use wasmer::Memory;

pub trait Read<T> {
    /// Read the value contained in the given memory at the current pointer
    /// offset.
    ///
    /// # Return
    /// A result with an Error if for some reason the binding failed to read
    /// the offset returned. It can be a cast error for example.
    ///
    /// Otherwise, a success with the value red at the point.
    ///
    /// # Example
    /// ```ignore
    /// let get_string = instance
    ///     .exports
    ///     .get_native_function::<(), StringPtr>("getString")?;
    /// let str_ptr = get_string.call()?;
    /// let string = str_ptr.read(memory)?;
    /// ```
    fn read(&self, memory: &Memory) -> anyhow::Result<T>;
    /// Read the size as indicated in the [AssemblyScript object header](https://www.assemblyscript.org/memory.html#internals)
    ///
    /// # Return
    /// A result with an Error if for some reason the binding failed to read
    /// the offset returned. It can be a cast error for example.
    ///
    /// Otherwise, a success with the size.
    ///
    /// # Example
    /// ```ignore
    /// let get_string = instance
    ///     .exports
    ///     .get_native_function::<(), StringPtr>("getString")?;
    /// let str_ptr = get_string.call()?;
    /// let size: u32 = str_ptr.size(memory)?;
    /// ```
    fn size(&self, memory: &Memory) -> anyhow::Result<u32>;
}

pub trait Write<T> {
    /// Try to write in the given environment a new value thanks to the
    /// AssemblyScript runtime.
    ///
    /// # Return
    /// A result with an Error if the given environment don't export the
    /// [AssemblyScript Runtime](https://www.assemblyscript.org/garbage-collection.html#runtime-interface)
    /// or if for some reason the binding failed to read the offset returned.
    ///
    /// Otherwise, the result return a success containing the new pointer.
    ///
    /// # Example
    /// ```ignore
    /// let mut env = Env::default();
    /// env.init(&instance)?;
    /// let str_ptr = StringPtr::alloc(&"hello return".to_string(), &env)?;
    /// ```
    fn alloc(value: &T, env: &Env) -> anyhow::Result<Box<Self>>;
    /// Try to write in the given environment a value. If the size is
    /// different, we procede to free the previous string and realloc a new
    /// pointer.
    ///
    /// # Return
    /// A result with an Error if the given environment don't export the
    /// [AssemblyScript Runtime](https://www.assemblyscript.org/garbage-collection.html#runtime-interface)
    /// or if for some reason the binding failed to read the offset returned.
    ///
    /// Otherwise, the result return a success containing pointer. This pointer
    /// can be another if a reallocation occured.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let mut env = Env::default();
    /// env.init(&instance)?;
    /// let string = str_ptr.write(&"hello return".to_string(), &env)?;
    /// ```
    fn write(&mut self, value: &T, env: &Env) -> anyhow::Result<Box<Self>>;
    /// Unpin the pointer
    fn free(self, env: &Env) -> anyhow::Result<()>;
}

#[derive(Debug)]
pub enum Error {
    Mem(&'static str),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Mem(err) => write!(f, "{}", err),
        }
    }
}

impl std::error::Error for Error {}