Skip to main content

hello_graph/
hello_graph.rs

1use keket::{
2    database::{AssetDatabase, path::AssetPathStatic},
3    fetch::file::FileAssetFetch,
4    protocol::bundle::BundleAssetProtocol,
5};
6use keket_graph::{
7    node::AssetNode,
8    protocol::{AssetTree, AssetTreeProcessor},
9};
10use keket_graph_derive::AssetTree;
11use serde::{Deserialize, Serialize};
12use std::error::Error;
13
14fn main() -> Result<(), Box<dyn Error>> {
15    // /* ANCHOR: main */
16    let mut database = AssetDatabase::default()
17        .with_protocol(BundleAssetProtocol::new(
18            "custom",
19            // AssetTreeProcessor handles deserialization of the custom asset
20            // as single component. That component will report its dependencies
21            // to load.
22            AssetTreeProcessor::<CustomAsset>::new(|bytes| {
23                Ok(serde_json::from_slice::<CustomAsset>(&bytes)?)
24            }),
25        ))
26        .with_fetch(FileAssetFetch::default().with_root("resources"));
27
28    // Create asset node and ensure it is being loaded.
29    let asset = AssetNode::<CustomAsset>::new("custom://part1.json");
30    asset.ensure(&mut database)?;
31
32    // Wait until the database is not busy, which means all assets are loaded.
33    while database.is_busy() {
34        database.maintain()?;
35    }
36
37    // Resolve the asset and read its contents.
38    // This will also resolve all dependencies of the asset.
39    let contents = asset
40        .resolve(&database)?
41        .read_unchecked()
42        .contents(&database);
43    println!("Custom chain contents: {contents:?}");
44    // /* ANCHOR_END: main */
45    Ok(())
46}
47
48/* ANCHOR: custom_asset */
49// This example demonstrates how to create a custom asset type that can
50// have dependencies on other assets. The `CustomAsset` struct is defined
51// with a `content` field and an optional `next` field that points to another
52// `CustomAsset`.
53#[derive(Debug, Default, Serialize, Deserialize, AssetTree)]
54struct CustomAsset {
55    content: String,
56    // The `next` field is annotated with `#[asset_deps]` to indicate that it is
57    // an asset dependency that has to be loaded along with this asset.
58    #[serde(default)]
59    #[asset_deps]
60    next: Option<AssetNode<CustomAsset>>,
61}
62
63impl CustomAsset {
64    fn contents(&self, database: &AssetDatabase) -> String {
65        let mut result = self.content.as_str().to_owned();
66        if let Some(next) = self.next.as_ref() {
67            result.push(' ');
68            if let Ok(resolved) = next.resolve(database) {
69                result.push_str(&resolved.read_unchecked().contents(database));
70            }
71        }
72        result
73    }
74}
75/* ANCHOR_END: custom_asset */