ark-api-ffi 0.16.0

Ark low-level Wasm FFI API
Documentation
define_api_id!(0x2110_e04a_32df_fab1, "storage-v1");

use crate::FFIResult;

/// Handle to a store
pub type StoreHandle = u64;
/// Handle to a async get operation on a store
pub type AsyncGetHandle = u64;

#[ark_api_macros::ark_bindgen(imports = "ark-storage-v1")]
mod storage {
    use super::*;

    /// Storage realm, where a store exists.
    #[repr(u32)]
    #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
    pub enum StoreRealm {
        /// Store is not persisted and only available while open in the current module instance.
        ///
        /// This is mostly useful for testing purposes, or possibly to be able to "swap" out and
        /// use more than 2 GB of memory in a Wasm module.
        ModuleInstance = 1,

        /// Store is persisted only on the local device, store names are device-wide for any module
        /// to access.
        ///
        /// This is useful, for instance, for testing purposes before creating a global cache, as
        /// well as for keeping some local caches in modules.
        DeviceShared = 2,

        /// Store is persisted only on the local device, store names are device-wide for any module
        /// to access.
        ///
        /// This is useful, for instance, for testing purposes before creating a global cache, as
        /// well as for keeping some local caches in modules.
        DeviceUser = 4,

        /// Store is persisted on the local device and asynchronously and automatically
        /// synchronized globally for other users.
        GlobalShared = 3,

        /// Store is specific to a single user, is persisted on the local device as well
        /// as asynchronously automatically synchronized globally.
        ///
        /// This means that each user will get their own version of a store with the same name
        GlobalUser = 5,
    }

    /// Is this store sync or async?
    #[repr(u32)]
    #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
    pub enum StoreMode {
        /// All the store methods are sync. Upon creation, there's an initial refresh of all the
        /// keys *and* values, spawned in the background. The first method call will block on this
        /// initial refresh being done.
        ///
        /// As a matter of fact, this will fetch all the values, which can be quite slow for large
        /// stores. It is recommended to only use this for small stores, and to request open them
        /// as soon as possible in the applet's life cycle, e.g. in the `ark_initialize`
        /// entrypoint.
        ///
        /// Individual values are expected to be obtained through `immediate_get`.
        /// Using `async_get` on such a store will work fine, but add unnecessary overhead in terms
        /// of performance and it will be more tedious.
        Sync,

        /// The store provides an `async get` method, and all other methods are sync. Upon
        /// creation, there's an initial refresh of all the keys only, spawned in the background.
        /// The first method call will block on this initial refresh being done.
        ///
        /// Individual values are expected to be obtained through `async_get`. Using
        /// `immediate_get` on such a store will block the main thread until the value is done
        /// downloading.
        Async,
    }

    extern "C" {
        /// Open a store and make it available for the module
        ///
        /// This can be a very expensive operation for [`StoreRealm::Global]` as it will synchronize and download latest data.
        /// Prefer to call this early in module initialization
        #[deprecated_infallible]
        pub fn store_open(realm: StoreRealm, name: &str) -> StoreHandle;

        /// Open a store and make it available for the module
        ///
        /// This can be a very expensive operation for [`StoreRealm::Global]` as it will synchronize and download latest data.
        /// Prefer to call this early in module initialization
        ///
        /// Note: This does not support [`StoreRealm::DeviceUser`] or [`StoreRealm::GlobalUser`], use `store_open3` for that
        pub fn store_open2(realm: StoreRealm, mode: StoreMode, name: &str) -> StoreHandle;

        /// Open a store and make it available for the module
        ///
        /// This can be a very expensive operation for [`StoreRealm::Global]` as it will synchronize and download latest data.
        /// Prefer to call this early in module initialization
        pub fn store_open3(
            realm: StoreRealm,
            realm_user_id: &[u8],
            mode: StoreMode,
            name: &str,
        ) -> StoreHandle;

        /// Close a store
        #[deprecated_infallible]
        pub fn store_close(handle: StoreHandle);

        /// Set a key value in a store
        ///
        /// This is a fast call that updates the store in-memory or on-disk
        #[deprecated_infallible]
        pub fn immediate_insert(store: StoreHandle, key: &[u8], value: &[u8]);

        /// Remove key value in a store
        ///
        /// This is a fast call that updates the store in-memory or on-disk
        #[deprecated_infallible]
        pub fn immediate_remove(store: StoreHandle, key: &[u8]);

        /// Get the value of a key, for a store opened in `StoreMode::Sync` mode.
        ///
        /// This is a fast call, as a sync store synchronizes all the data in real-time in the
        /// background.
        ///
        /// Using this method with a store opened in `StoreMode::Async` mode will block the main
        /// thread, waiting for the value to be downloaded if it is not present in the local cache.
        /// It is recommended to use `async_get` for such stores.
        ///
        /// # Return
        ///
        /// If a key is found, will return a vector filled with the entry encoded as plain bytes.
        /// If a key is not found, will fail with `NotFound`.
        pub fn immediate_get(store: StoreHandle, key: &[u8]) -> FFIResult<Vec<u8>>;

        /// Get list of all keys in a single byte buffer
        ///
        /// This can be a potentially quite large list although only contains the keys, not the values.
        ///
        /// # Return
        ///
        /// The list of all the keys is returned in a binary blob.
        /// The data is formatted in a single binary buffer that starts with a `u32` count of keys and then each
        /// key is following with a `u32` length of the key and then the contents of the key
        #[deprecated_infallible]
        pub fn immediate_list(store: StoreHandle) -> Vec<u8>;

        /// Get the value of a key, for a store opened in `StoreMode::Async` mode.
        ///
        /// This returns a handle to an asynchronous operation that will first try to retrieve a
        /// cached version of the value, or fetch it from a remote store if not found.
        ///
        /// The final value may be retrieved with `async_get_is_ready`.
        ///
        /// Using this method with a store opened in `StoreMode::Sync` mode will work just fine,
        /// but add unnecessary overhead and is more tedious; prefer using `immediate_get` for such
        /// stores.
        pub fn async_get(store: StoreHandle, key: &[u8]) -> AsyncGetHandle;

        /// Attempts to read the value requested by a previous `async_get` call.
        ///
        /// # Return
        ///
        /// If the async request is done:
        ///
        /// - If a key is found, will return a vector filled with the entry encoded as plain bytes.
        /// - If a key is not found, will fail with `NotFound`.
        ///
        /// If the async request is not done yet, will fail with `Unavailable`.
        pub fn async_get_ready(handle: AsyncGetHandle) -> FFIResult<Vec<u8>>;
    }
}

pub use storage::*;