Asset Reference
AssetRef
is a thin wrapper around asset path and optional cached asset handle.
The goal here was to allow to reduce resolving asset handles to one resolution for given asset reference - searching for asset handle by asset path is unnecessary work to do everytime we point to an asset by path and need to perform operations on its handle, so with asset reference we can resolve asset handle once and reuse its cached handle for future database operations.
Additional justification for asset references is serialization - this is preferred way to reference assets in serializable data, so once container gets deserializaed into typed data, asset handle resolution will happen only at first time.
use keket::{
database::{reference::AssetRef, AssetDatabase},
fetch::file::FileAssetFetch,
protocol::bundle::{
BundleAssetProtocol, BundleWithDependencies, BundleWithDependenciesProcessor,
},
};
use serde::Deserialize;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let mut database = AssetDatabase::default()
.with_protocol(BundleAssetProtocol::new("custom", CustomAssetProcessor))
.with_fetch(FileAssetFetch::default().with_root("resources"));
let handle = database.ensure("custom://part1.json")?;
while database.is_busy() {
database.maintain()?;
}
let contents = handle.access::<&CustomAsset>(&database).contents(&database);
println!("Custom chain contents: {:?}", contents);
Ok(())
}
#[derive(Debug, Default, Deserialize)]
struct CustomAsset {
content: String,
// Asset references are used to store path and cached handle. They serialize as asset paths.
// They can be used where we need to have an ability to reference asset by path, and ask
// for handle once instead of everytime as with asset paths.
#[serde(default)]
next: Option<AssetRef>,
}
impl CustomAsset {
fn contents(&self, database: &AssetDatabase) -> String {
let mut result = self.content.as_str().to_owned();
if let Some(next) = self.next.as_ref() {
result.push(' ');
if let Ok(resolved) = next.resolve(database) {
result.push_str(&resolved.access::<&Self>().contents(database));
}
}
result
}
}
struct CustomAssetProcessor;
impl BundleWithDependenciesProcessor for CustomAssetProcessor {
type Bundle = (CustomAsset,);
fn process_bytes(
&mut self,
bytes: Vec<u8>,
) -> Result<BundleWithDependencies<Self::Bundle>, Box<dyn Error>> {
let asset = serde_json::from_slice::<CustomAsset>(&bytes)?;
let dependency = asset
.next
.as_ref()
.map(|reference| reference.path().clone());
Ok(BundleWithDependencies::new((asset,)).maybe_dependency(dependency))
}
}
use keket::{
database::{reference::AssetRef, AssetDatabase},
fetch::file::FileAssetFetch,
protocol::bundle::{
BundleAssetProtocol, BundleWithDependencies, BundleWithDependenciesProcessor,
},
};
use serde::Deserialize;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let mut database = AssetDatabase::default()
.with_protocol(BundleAssetProtocol::new("custom", CustomAssetProcessor))
.with_fetch(FileAssetFetch::default().with_root("resources"));
let handle = database.ensure("custom://part1.json")?;
while database.is_busy() {
database.maintain()?;
}
let contents = handle.access::<&CustomAsset>(&database).contents(&database);
println!("Custom chain contents: {:?}", contents);
Ok(())
}
#[derive(Debug, Default, Deserialize)]
struct CustomAsset {
content: String,
// Asset references are used to store path and cached handle. They serialize as asset paths.
// They can be used where we need to have an ability to reference asset by path, and ask
// for handle once instead of everytime as with asset paths.
#[serde(default)]
next: Option<AssetRef>,
}
impl CustomAsset {
fn contents(&self, database: &AssetDatabase) -> String {
let mut result = self.content.as_str().to_owned();
if let Some(next) = self.next.as_ref() {
result.push(' ');
if let Ok(resolved) = next.resolve(database) {
result.push_str(&resolved.access::<&Self>().contents(database));
}
}
result
}
}
struct CustomAssetProcessor;
impl BundleWithDependenciesProcessor for CustomAssetProcessor {
type Bundle = (CustomAsset,);
fn process_bytes(
&mut self,
bytes: Vec<u8>,
) -> Result<BundleWithDependencies<Self::Bundle>, Box<dyn Error>> {
let asset = serde_json::from_slice::<CustomAsset>(&bytes)?;
let dependency = asset
.next
.as_ref()
.map(|reference| reference.path().clone());
Ok(BundleWithDependencies::new((asset,)).maybe_dependency(dependency))
}
}