krust_asset_loader/
lib.rs

1extern crate serde_json;
2#[macro_use] extern crate failure;
3
4use std::path::{Path, PathBuf};
5use std::fs;
6use std::io::{self, Read};
7use std::ffi;
8
9#[derive(Debug, Fail)]
10pub enum Error {
11    #[fail(display = "I/O error")]
12    Io(#[cause] io::Error),
13    #[fail(display = "Failed to read CString from file that contains 0")]
14    FileContainsNil,
15    #[fail(display = "Failed get executable path")]
16    FailedToGetExePath,
17}
18
19impl From<io::Error> for Error {
20    fn from(other: io::Error) -> Self {
21        Error::Io(other)
22    }
23}
24
25pub struct AssetLoader {
26    root_path: PathBuf,
27}
28
29impl AssetLoader {
30    pub fn new(rel_path: &Path) -> Result<AssetLoader, Error> {
31        let exe_file_name = ::std::env::current_exe().map_err(|_| Error::FailedToGetExePath)?;
32        let exe_path = exe_file_name.parent().ok_or(Error::FailedToGetExePath)?;
33
34        Ok(AssetLoader {
35            root_path: exe_path.join(rel_path)
36        })
37    }
38
39    pub fn load_cstring(&self, resource_name: &str) -> Result<ffi::CString, Error> {
40        let mut file = fs::File::open(
41            resource_name_to_path(&self.root_path, resource_name)
42        )?;
43
44        // allocate buffer of the same size as file
45        let mut buffer: Vec<u8> = Vec::with_capacity(
46            file.metadata()?.len() as usize + 1
47        );
48        file.read_to_end(&mut buffer)?;
49
50        // check for nul byte
51        if buffer.iter().find(|i| **i == 0).is_some() {
52            return Err(Error::FileContainsNil);
53        }
54
55        Ok(unsafe { ffi::CString::from_vec_unchecked(buffer) })
56    }
57
58    pub fn load_string(&self, resource_name: &str) -> PathBuf {
59        resource_name_to_path(&self.root_path, resource_name)
60    }
61
62    pub fn load_json(&self, resource_name: &str) -> serde_json::Value {
63        let mut file = fs::File::open(self.load_string(resource_name)).expect("Unable to load JSON");
64        let mut data = String::new();
65        file.read_to_string(&mut data).unwrap();
66
67        serde_json::from_str(&data).expect("JSON was not well-formatted")
68    }
69}
70
71fn resource_name_to_path(root_dir: &Path, location: &str) -> PathBuf {
72    let mut path: PathBuf = root_dir.into();
73
74    for part in location.split("/") {
75        path = path.join(part);
76    }
77    
78    path
79}