Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Async loading wrapper

FutureAssetFetch allows to asynchronously load requested bytes in async/await futures. It's similar to DeferredAssetFetch, although it expects provided custom async function that will handle loading asset bytes with custom async/await compatible libraries like tokio.

use anput::bundle::DynamicBundle;
use keket::{
    database::{AssetDatabase, path::AssetPathStatic},
    fetch::{AssetBytesAreReadyToProcess, future::FutureAssetFetch},
    protocol::bytes::BytesAssetProtocol,
};
use std::{error::Error, path::PathBuf};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let mut database = AssetDatabase::default()
        .with_protocol(BytesAssetProtocol)
        // Future asset fetch uses async function to handle providing
        // asset bytes asynchronously with async/await.
        .with_fetch(FutureAssetFetch::new(tokio_load_file_bundle));

    let package = database.ensure("bytes://package.zip")?;

    // Run maintain passes to load and process loaded bytes.
    while !package.is_ready_to_use(&database) {
        database.maintain()?;
        tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
    }

    println!(
        "Package byte size: {}",
        package.access::<&Vec<u8>>(&database).len()
    );

    Ok(())
}

async fn tokio_load_file_bundle(path: AssetPathStatic) -> Result<DynamicBundle, Box<dyn Error>> {
    let file_path = PathBuf::from("resources").join(path.path());

    let bytes = tokio::fs::read(&file_path).await?;

    let mut bundle = DynamicBundle::default();
    bundle
        .add_component(AssetBytesAreReadyToProcess(bytes))
        .map_err(|_| format!("Failed to add bytes to bundle for asset: {path}"))?;
    Ok(bundle)
}

And here is async function that handles loading bytes with tokio:

use anput::bundle::DynamicBundle;
use keket::{
    database::{AssetDatabase, path::AssetPathStatic},
    fetch::{AssetBytesAreReadyToProcess, future::FutureAssetFetch},
    protocol::bytes::BytesAssetProtocol,
};
use std::{error::Error, path::PathBuf};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let mut database = AssetDatabase::default()
        .with_protocol(BytesAssetProtocol)
        // Future asset fetch uses async function to handle providing
        // asset bytes asynchronously with async/await.
        .with_fetch(FutureAssetFetch::new(tokio_load_file_bundle));

    let package = database.ensure("bytes://package.zip")?;

    // Run maintain passes to load and process loaded bytes.
    while !package.is_ready_to_use(&database) {
        database.maintain()?;
        tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
    }

    println!(
        "Package byte size: {}",
        package.access::<&Vec<u8>>(&database).len()
    );

    Ok(())
}

async fn tokio_load_file_bundle(path: AssetPathStatic) -> Result<DynamicBundle, Box<dyn Error>> {
    let file_path = PathBuf::from("resources").join(path.path());

    let bytes = tokio::fs::read(&file_path).await?;

    let mut bundle = DynamicBundle::default();
    bundle
        .add_component(AssetBytesAreReadyToProcess(bytes))
        .map_err(|_| format!("Failed to add bytes to bundle for asset: {path}"))?;
    Ok(bundle)
}