Skip to main content

rate_core/
assets.rs

1use anyhow::Error;
2use flate2::read::GzDecoder;
3use std::collections::HashMap;
4use std::io::Read;
5use std::sync::Arc;
6use tar::Archive;
7use thiserror::Error;
8
9#[derive(Debug, Error)]
10enum Reason {
11    #[error("wrong format")]
12    WrongFormat,
13}
14
15#[derive(Clone, Debug)]
16pub struct Assets {
17    files: Arc<HashMap<String, Vec<u8>>>,
18}
19
20impl Assets {
21    /// Expected gzipped tar file contents.
22    pub fn parse(assets: &[u8]) -> Result<Assets, Error> {
23        let tar = GzDecoder::new(assets);
24        let mut archive = Archive::new(tar);
25        let mut files = HashMap::new();
26        for entry in archive.entries()? {
27            let mut entry = entry?;
28            let mut data = Vec::new();
29            entry.read_to_end(&mut data)?;
30            if !data.is_empty() {
31                let name = entry
32                    .path()?
33                    .to_str()
34                    .ok_or(Reason::WrongFormat)?
35                    .to_owned();
36                #[cfg(debug_assertions)]
37                log::trace!("Register asset file: {}", name);
38                files.insert(name, data);
39            }
40        }
41        Ok(Self {
42            files: Arc::new(files),
43        })
44    }
45
46    pub fn get(&self, path: &str) -> Option<&[u8]> {
47        self.files.get(path).map(Vec::as_ref)
48    }
49
50    pub fn iter(&self) -> impl Iterator<Item = (&str, &[u8])> {
51        self.files.iter().map(|(s, d)| (s.as_ref(), d.as_ref()))
52    }
53}
54
55pub mod build {
56    use anyhow::Error;
57    use flate2::write::GzEncoder;
58    use flate2::Compression;
59    use std::fs::File;
60
61    pub fn pack(dir: &str, to: &str) -> Result<(), Error> {
62        let tar_gz = File::create(to)?;
63        let enc = GzEncoder::new(tar_gz, Compression::default());
64        let mut tar = tar::Builder::new(enc);
65        tar.append_dir_all(".", dir)?;
66        Ok(())
67    }
68}