11_custom_protocol_simple/
11_custom_protocol_simple.rs1use keket::{
2 database::{AssetDatabase, path::AssetPathStatic},
3 fetch::file::FileAssetFetch,
4 protocol::bundle::{
5 BundleAssetProtocol, BundleWithDependencies, BundleWithDependenciesProcessor,
6 },
7};
8use serde::Deserialize;
9use std::error::Error;
10
11fn main() -> Result<(), Box<dyn Error>> {
12 let mut database = AssetDatabase::default()
13 .with_protocol(BundleAssetProtocol::new("custom", CustomAssetProcessor))
15 .with_fetch(FileAssetFetch::default().with_root("resources"));
16
17 let handle = database.ensure("custom://part1.json")?;
19
20 while database.is_busy() {
22 database.maintain()?;
23 }
24
25 let contents = handle.access::<&CustomAsset>(&database).contents(&database);
26 println!("Custom chain contents: {contents:?}");
27
28 Ok(())
29}
30
31#[derive(Debug, Default, Deserialize)]
34struct CustomAsset {
35 content: String,
37 #[serde(default)]
39 next: Option<AssetPathStatic>,
40}
41impl CustomAsset {
44 fn contents(&self, database: &AssetDatabase) -> String {
45 let mut result = String::new();
47 let mut current = Some(self);
48 while let Some(asset) = current {
49 result.push_str(asset.content.as_str());
50 current = current
51 .as_ref()
52 .and_then(|asset| asset.next.as_ref())
53 .and_then(|path| path.find(database))
54 .and_then(|handle| handle.access_checked::<&Self>(database));
55 if current.is_some() {
56 result.push(' ');
57 }
58 }
59 result
60 }
61}
62
63struct CustomAssetProcessor;
65
66impl BundleWithDependenciesProcessor for CustomAssetProcessor {
67 type Bundle = (CustomAsset,);
69
70 fn process_bytes(
71 &mut self,
72 bytes: Vec<u8>,
73 ) -> Result<BundleWithDependencies<Self::Bundle>, Box<dyn Error>> {
74 let asset = serde_json::from_slice::<CustomAsset>(&bytes)?;
75 let dependency = asset.next.clone();
76 Ok(BundleWithDependencies::new((asset,)).maybe_dependency(dependency))
78 }
79}
80