ark-api 0.17.0-pre.15

Ark API
Documentation
//! # 🧰 Resource API
//!
//! This API is useful for embedding and accessing static resources in a module.
//!
//! ## Example usage
//!
//! In `Cargo.toml` for the module, define which static file resource the module wants to be able to access.
//!
//! ```toml
//! [package.metadata.ark]
//! include-files = [
//!     "assets/coin.wav",
//! ]
//! ```
//!
//! This will associate the file "assets/coin.wav" as a dependent static resource of the Ark module and
//! Ark will load it and make it available for the module before it is loaded.
//!
//! Inside the module one can then use `ark::resource::get("assets/coin.wav")` to get a slice to the
//! contents of the resource. This data is always loaded in memory and as such always available for the module.
//!
//! ## File roots
//!
//! If one has a shared workspace with multiple modules and want to share resources between them, or have a more
//! complex path for them, one can set one or multiple file roots for the included files in `Cargo.toml`.
//!
//! In the below example we have an `assets` folder that is located in a shared workspace directory relative to the
//! `Cargo.toml` file and where we want to include files from. Note that in this example the resource would be referenced
//! in the module with the `ark::resource::get("assets/coin.wav")`
//!
//! ```toml
//! [package.metadata.ark]
//! include-file-roots = [
//!     "../../assets",
//! include-files = [
//!     "coin.wav",
//! ]
//! ```
//!
//! It is also possible to have multiple roots specified. The file will then be loaded from the first root it is found in
//!
//! ## Alternatives
//!
//! This mechanism is meant for resources that are not trivially small (say large than 1 KB) and enables Ark to compress, de-duplicate and
//! cache the resources efficiently for distribution, storage, and loading.
//!
//! But if one has very small file resources, where compression and caching is not as beneficial, then it can be more optimal and easier
//! to embed the file directly into the module binary instead with the Rust standard [`include_bytes!`] macro

use crate::ffi::ErrorCode;

#[doc(hidden)]
pub use crate::ffi::resource_v1::API as FFI_API;

pub use crate::ffi::resource_v1::ResourceHandleRepr;

/// Retrieves named static resource
pub fn get(name: &'static str) -> Option<&'static [u8]> {
    get_dynamic(name)
}

/// Retrieves named static resource in a unsafe manner
///
/// Takes a non-'static str as parameter.
/// [`get`] should be preferred over this.
pub fn get_dynamic(name: &str) -> Option<&'static [u8]> {
    match crate::ffi::resource_v0::get_static(name) {
        Ok(r) => Some(unsafe { std::slice::from_raw_parts(r.ptr as *const u8, r.size as usize) }),
        Err(ErrorCode::NotFound) => None,
        Err(error_code) => panic!(
            "Resource get '{}' failed with code {}",
            name, error_code as u32
        ),
    }
}

/// Represents a handle to unique resource
///
/// In-process serialization is supported through `speedy`. However, this
/// handle should not be persisted across module sessions.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "with_speedy", derive(speedy::Writable, speedy::Readable))]
pub struct ResourceHandle {
    inner: ResourceHandleRepr,
}

impl ResourceHandle {
    /// Request the latest version of a resource given the provided name
    ///
    /// This will start downloading the resource if it isn't present in Ark
    #[inline]
    pub fn request(name: &str) -> Self {
        let inner = crate::ffi::resource_v1::request_resource_by_name(name);
        Self { inner }
    }

    /// Retrieve the resource's data by copying it into Wasm memory
    ///
    /// Returns [`None`] if the resource hasn't finished downloading
    ///
    /// If you only want to check if a resource is ready, use [`Self::is_ready`] instead
    #[inline]
    pub fn try_retrieve(&self) -> Option<Vec<u8>> {
        match crate::ffi::resource_v1::try_retrieve(self.inner) {
            Ok(bytes) => Some(bytes),
            Err(ErrorCode::Unavailable) => None,
            Err(error_code) => panic!(
                "Failed retrieving resource bytes with code: {}",
                error_code as u32
            ), // TODO: display name?
        }
    }

    /// Check if the resource is available for use
    #[inline]
    pub fn is_ready(&self) -> bool {
        match crate::ffi::resource_v1::is_ready(self.inner) {
            Ok(()) => true,
            Err(ErrorCode::Unavailable) => false,
            Err(error_code) => panic!("Failed `ResourceHandle::is_ready`: {}", error_code as u32),
        }
    }

    /// Retrieve the raw inner [`ResourceHandleRepr`]
    ///
    /// Useful for passing to other Ark APIs that can operate on resources
    ///
    /// TODO: return a concrete type that can be shared between Ark APIs
    #[inline]
    pub fn raw(&self) -> ResourceHandleRepr {
        self.inner
    }
}