28_protocol_extract/
28_protocol_extract.rs1use keket::{
2 database::{
3 AssetDatabase,
4 handle::AssetHandle,
5 path::{AssetPath, AssetPathStatic},
6 },
7 fetch::file::FileAssetFetch,
8 protocol::AssetProtocol,
9 third_party::anput::{bundle::DynamicBundle, world::World},
10};
11use std::error::Error;
12
13fn main() -> Result<(), Box<dyn Error>> {
14 let mut database = AssetDatabase::default()
15 .with_protocol(CustomAssetProtocol)
17 .with_fetch(FileAssetFetch::default().with_root("resources"))
18 .with_event(|event| {
19 println!("Asset closure event: {event:#?}");
20 Ok(())
21 });
22
23 database.ensure("custom://lorem.txt?uppercase")?;
26
27 while database.is_busy() {
28 database.maintain()?;
29 }
30
31 let handle = database.find("custom://lorem.txt").unwrap();
33 let (contents, meta) = handle.access::<(&String, &Meta)>(&database);
34 println!("Custom asset meta: {meta:?}");
35 println!("Custom asset contents: {contents:?}");
36
37 Ok(())
38}
39
40#[derive(Debug, Default)]
41struct Meta {
42 uppercase: bool,
43}
44
45struct CustomAssetProtocol;
46
47impl AssetProtocol for CustomAssetProtocol {
48 fn name(&self) -> &str {
49 "custom"
50 }
51
52 fn extract_bundle_from_path(&self, path: &AssetPath) -> Result<DynamicBundle, Box<dyn Error>> {
54 let mut meta = Meta::default();
55 if path.has_meta_key("uppercase") {
56 meta.uppercase = true;
57 }
58 Ok(DynamicBundle::new(meta).unwrap())
59 }
60
61 fn rewrite_path(&self, path: AssetPathStatic) -> Result<AssetPathStatic, Box<dyn Error>> {
63 Ok(AssetPathStatic::from_parts(
64 path.protocol(),
65 path.path(),
66 "",
67 ))
68 }
69
70 fn process_bytes(
71 &mut self,
72 handle: AssetHandle,
73 storage: &mut World,
74 bytes: Vec<u8>,
75 ) -> Result<(), Box<dyn Error>> {
76 let uppercase = storage.component::<true, Meta>(handle.entity())?.uppercase;
77 let mut contents = String::from_utf8(bytes)?;
78 if uppercase {
79 contents = contents.to_uppercase();
80 }
81 storage.insert(handle.entity(), (contents,))?;
82 Ok(())
83 }
84}