ark-api-ffi 0.16.0

Ark low-level Wasm FFI API
Documentation
use crate::FFIResult;
use bytemuck::CheckedBitPattern;
use bytemuck::NoUninit;

// Types used in the return position must implement `Default` when calling the
// generated safe methods, as they are created on the module side before passing
// a mutable pointer to them for the host to actually fill in.
//
// Note that you'll still need to derive `NoUninit` and `CheckedBitPattern` manually
// on structs. The reason for this is that you may also want to derive `Pod` and `Zeroable`
// instead, and there's currently no way of figuring out which to derive automatically.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, NoUninit, CheckedBitPattern)]
#[repr(C)]
pub struct IsReady {
    pub is_ready: bool,
    // Again, more details on why this is necessary later, but basically, if this wasn't
    // here then there would be padding bytes in this struct layout so that `size`
    // could be aligned. We take those padding bytes up with "explicit"/"manual" padding
    // here instead, so that we can satisfy the requirements of `NoUninit`
    pub _pad: [u8; 3],
    pub size: u32,
}

// The ark_bindgen macro automatically synthesizes proper FFI bindings from
// more idiomatic Rust function signatures.
#[ark_api_macros::ark_bindgen(imports = "example-automatic")]
// The module name, in this case `example` is the "namespace" for the FFI
// functions. This name will be used to prefix each function in the
// `extern "C"` block that **must** be inside the module.
mod example {
    use super::*;

    // Enums used as FFI parameters need to be moved into the procedural macro
    // as the macro will extract the primitive type to convert to
    // from the #[repr(primitive_type)]. This means that #[repr(primitive_type)]
    // must be present or you'll get an error message.
    // #[derive(IntoPrimitive, TryFromPrimitive, NoUninit, CheckedBitPattern)] are
    // then generated for you on enums automatically.
    #[derive(Copy, Clone, Debug)]
    #[repr(u32)]
    pub enum State {
        SomeStateX,
        SomeStateY,
    }

    extern "C" {
        pub fn is_ready(
            // We just pass a &str like normal, it will be converted
            // into a pointer + length for you, the same for slices
            name: &str,
            // FFI safe types such as u32 are passed through transparently
            max: u32,
            // We just pass an enum like normal, it will be converted into
            // its primitive type for you.
            state: State,
            // FFIResult<T> is a special type in ark_api_ffi that is recognized
            // by the proc macro. It automatically converts the T into a *mut T
            // as the last parameter, with `ErrorCode` as the actual return type
        ) -> FFIResult<IsReady>;

        // It's possible to return Vec of bytes (and only for this type!) from
        // the host.
        pub fn ret_byte_vector() -> FFIResult<Vec<u8>>;

        // And also a string!
        pub fn ret_string() -> FFIResult<String>;

        // Return nothing in particular, but can still generate an error the user can react to.
        pub fn works() -> FFIResult<()>;

        // Returns a number, infallible mode. Note the host can still run into internal errors and
        // abort execution of the Ark module. In this case, the Ark module developer can't do
        // anything about it, so this function returns a plain type instead of the `FFIResult`
        // type.
        pub fn infallible_number(x: u32) -> u32;
    }
}

/// Due to some limitations on how attribute macro currently work, our proc
/// macro needs to be placed on an inner module. This means that other code
/// using us has to have an unnecessary level of indirection to use the types/
/// functions in that module, so instead we just re-export everything so they
/// only need to access the single top level module to get everything
pub use example::*;