1use anyhow::{bail, Context, Result};
20use khora_core::asset::AssetSource;
21use std::path::{Path, PathBuf};
22
23use super::{AssetIo, AssetWriter};
24
25pub struct FileLoader {
30 root: PathBuf,
31}
32
33impl FileLoader {
34 pub fn new(root: impl Into<PathBuf>) -> Self {
36 Self { root: root.into() }
37 }
38
39 pub fn root(&self) -> &Path {
41 &self.root
42 }
43}
44
45impl AssetIo for FileLoader {
46 fn load_bytes(&mut self, source: &AssetSource) -> Result<Vec<u8>> {
47 match source {
48 AssetSource::Path(rel) => {
49 let full_path = self.root.join(rel);
50 std::fs::read(&full_path)
51 .with_context(|| format!("Failed to read asset: {:?}", full_path))
52 }
53 AssetSource::Packed { .. } => {
54 bail!("FileLoader does not support Packed sources")
55 }
56 }
57 }
58}
59
60impl AssetWriter for FileLoader {
61 fn write_bytes(&self, rel_path: &Path, bytes: &[u8]) -> Result<()> {
62 let full_path = self.root.join(rel_path);
63 if let Some(parent) = full_path.parent() {
64 std::fs::create_dir_all(parent).with_context(|| {
65 format!("Failed to create parent directory for {:?}", full_path)
66 })?;
67 }
68 std::fs::write(&full_path, bytes)
69 .with_context(|| format!("Failed to write asset: {:?}", full_path))
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use tempfile::tempdir;
77
78 #[test]
79 fn write_bytes_creates_parent_dirs() {
80 let dir = tempdir().unwrap();
81 let loader = FileLoader::new(dir.path());
82 loader
83 .write_bytes(Path::new("scenes/default.kscene"), b"SCN")
84 .unwrap();
85 let written = std::fs::read(dir.path().join("scenes").join("default.kscene")).unwrap();
86 assert_eq!(written, b"SCN");
87 }
88
89 #[test]
90 fn round_trip_via_load_bytes() {
91 let dir = tempdir().unwrap();
92 let loader = FileLoader::new(dir.path());
93 loader
94 .write_bytes(Path::new("textures/foo.png"), b"PNG")
95 .unwrap();
96
97 let mut reader = FileLoader::new(dir.path());
98 let bytes = reader
99 .load_bytes(&AssetSource::Path(PathBuf::from("textures/foo.png")))
100 .unwrap();
101 assert_eq!(bytes, b"PNG");
102 }
103}