Skip to main content

web_static_pack_packer/
pack.rs

1//! Pack helpers. Contains [Builder], builder for [Pack].
2
3use crate::{
4    common::{PACK_FILE_MAGIC, PACK_FILE_VERSION, file::File, pack::Pack, pack_path::PackPath},
5    file_pack_path::FilePackPath,
6};
7use anyhow::{Error, bail};
8use rkyv::{api::high::to_bytes_in, rancor, ser::writer::IoWriter, util::AlignedVec};
9use std::{
10    collections::{HashMap, hash_map},
11    fs, io,
12    path::Path,
13};
14
15/// Main builder for `pack`. Inside it keeps list of [File] under respective
16/// [PackPath].
17#[derive(Debug)]
18pub struct Builder {
19    files_by_pack_path: HashMap<PackPath, File>,
20}
21impl Builder {
22    /// Creates empty [self] to be filled with files.
23    pub fn new() -> Self {
24        let files_by_pack_path = HashMap::<PackPath, File>::new();
25
26        Self { files_by_pack_path }
27    }
28
29    /// Adds file to the `pack`.
30    pub fn file_pack_path_add(
31        &mut self,
32        file_pack_path: FilePackPath,
33    ) -> Result<(), Error> {
34        let entry = match self.files_by_pack_path.entry(file_pack_path.pack_path) {
35            hash_map::Entry::Occupied(_entry) => {
36                bail!("file on specified path already exist");
37            }
38            hash_map::Entry::Vacant(entry) => entry,
39        };
40
41        entry.insert(file_pack_path.file);
42
43        Ok(())
44    }
45
46    /// Adds collection of files to the `pack`.
47    pub fn file_pack_paths_add(
48        &mut self,
49        file_pack_paths: impl IntoIterator<Item = FilePackPath>,
50    ) -> Result<(), Error> {
51        file_pack_paths
52            .into_iter()
53            .try_for_each(|file_pack_path| self.file_pack_path_add(file_pack_path))?;
54
55        Ok(())
56    }
57
58    /// Finalizes to builder, returning built [Pack].
59    pub fn finalize(self) -> Pack {
60        Pack {
61            files_by_path: self.files_by_pack_path,
62        }
63    }
64}
65
66fn store(
67    pack: &Pack,
68    mut writer: impl io::Write,
69) -> Result<(), Error> {
70    // NOTE: we rely on `pack` being 16-aligned two u64 at the beginning keeps
71    // alignment unchanged, but adding anything here will break it.
72    writer.write_all(&PACK_FILE_MAGIC.to_ne_bytes())?;
73    writer.write_all(&PACK_FILE_VERSION.to_ne_bytes())?;
74    to_bytes_in::<_, rancor::Error>(pack, IoWriter::new(writer))?;
75
76    Ok(())
77}
78
79/// Serializes `pack` to [AlignedVec]. Serialized data can be used with `load`
80/// method of loader.
81pub fn store_memory(pack: &Pack) -> Result<AlignedVec, Error> {
82    let mut buffer = AlignedVec::new();
83    store(pack, &mut buffer)?;
84    Ok(buffer)
85}
86
87/// Serializes `pack` to given file path Serialized data can be used with `load`
88/// method of loader.
89pub fn store_file(
90    pack: &Pack,
91    path: &Path,
92) -> Result<(), Error> {
93    let mut file = fs::File::create(path)?;
94
95    store(pack, &mut file)?;
96
97    file.sync_all()?;
98    drop(file);
99
100    Ok(())
101}