use alloc::string::String;
use concinnity_asset::cook;
use crate::components::FileKind;
use crate::ecs::asset_id::AssetId;
use crate::ecs::{Component, PayloadLocator};
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct File {
pub asset_id: AssetId,
pub path: String,
pub kind: Option<FileKind>,
pub locator: Option<PayloadLocator>,
}
impl File {
pub fn bake(args: cook::File) -> Self {
let kind = args
.kind
.clone()
.or_else(|| super::path_extension(&args.path).and_then(FileKind::from_ext));
Self {
asset_id: AssetId::default(),
path: args.path,
kind,
locator: None,
}
}
}
impl Component for File {
const NAME: &'static str = "File";
fn from_baked(bytes: &[u8]) -> Result<Self, crate::result::CnResult> {
Ok(crate::blob::decode_exact(bytes)?)
}
fn inject_locator(&mut self, locator: PayloadLocator) {
self.locator = Some(locator);
}
fn inject_name(&mut self, id: AssetId) {
self.asset_id = id;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_ext_maps_every_known_extension() {
let cases = [
("obj", FileKind::Obj),
("png", FileKind::Png),
("jpg", FileKind::Jpg),
("jpeg", FileKind::Jpeg),
("bmp", FileKind::Bmp),
("tga", FileKind::Tga),
("gif", FileKind::Gif),
("ttf", FileKind::Ttf),
("otf", FileKind::Otf),
("txt", FileKind::Txt),
("md", FileKind::Md),
("mtl", FileKind::Mtl),
];
for (ext, want) in cases {
assert_eq!(FileKind::from_ext(ext), Some(want.clone()));
assert_eq!(FileKind::from_ext(&ext.to_uppercase()), Some(want));
}
assert_eq!(FileKind::from_ext("zzz"), None);
}
#[test]
fn from_args_infers_kind_from_the_extension() {
let f = File::bake(cook::File {
path: "models/box.obj".into(),
kind: None,
});
assert_eq!(f.kind, Some(FileKind::Obj));
assert_eq!(f.path, "models/box.obj");
let g = File::bake(cook::File {
path: "data.obj".into(),
kind: Some(FileKind::Txt),
});
assert_eq!(g.kind, Some(FileKind::Txt));
let h = File::bake(cook::File {
path: "notes.zzz".into(),
kind: None,
});
assert_eq!(h.kind, None);
}
#[test]
fn is_mesh_is_true_only_for_obj() {
assert!(FileKind::Obj.is_mesh());
assert!(!FileKind::Png.is_mesh());
assert!(!FileKind::Ttf.is_mesh());
}
#[test]
fn file_args_and_kind_round_trip_through_json() {
let args = cook::File {
path: "x.png".into(),
kind: Some(FileKind::Png),
};
let value = serde_json::to_value(&args).unwrap();
let back: cook::File = serde_json::from_value(value).unwrap();
assert_eq!(back.path, "x.png");
assert_eq!(back.kind, Some(FileKind::Png));
assert_eq!(serde_json::to_string(&FileKind::Jpeg).unwrap(), "\"jpeg\"");
assert_eq!(File::bake(args).kind, Some(FileKind::Png));
}
}