use crate::{
common::{PACK_FILE_MAGIC, PACK_FILE_VERSION, file::File, pack::Pack, pack_path::PackPath},
file_pack_path::FilePackPath,
};
use anyhow::{Error, bail};
use rkyv::{api::high::to_bytes_in, rancor, ser::writer::IoWriter, util::AlignedVec};
use std::{
collections::{HashMap, hash_map},
fs, io,
path::Path,
};
#[derive(Debug)]
pub struct Builder {
files_by_pack_path: HashMap<PackPath, File>,
}
impl Builder {
pub fn new() -> Self {
let files_by_pack_path = HashMap::<PackPath, File>::new();
Self { files_by_pack_path }
}
pub fn file_pack_path_add(
&mut self,
file_pack_path: FilePackPath,
) -> Result<(), Error> {
let entry = match self.files_by_pack_path.entry(file_pack_path.pack_path) {
hash_map::Entry::Occupied(_entry) => {
bail!("file on specified path already exist");
}
hash_map::Entry::Vacant(entry) => entry,
};
entry.insert(file_pack_path.file);
Ok(())
}
pub fn file_pack_paths_add(
&mut self,
file_pack_paths: impl IntoIterator<Item = FilePackPath>,
) -> Result<(), Error> {
file_pack_paths
.into_iter()
.try_for_each(|file_pack_path| self.file_pack_path_add(file_pack_path))?;
Ok(())
}
pub fn finalize(self) -> Pack {
Pack {
files_by_path: self.files_by_pack_path,
}
}
}
fn store(
pack: &Pack,
mut writer: impl io::Write,
) -> Result<(), Error> {
writer.write_all(&PACK_FILE_MAGIC.to_ne_bytes())?;
writer.write_all(&PACK_FILE_VERSION.to_ne_bytes())?;
to_bytes_in::<_, rancor::Error>(pack, IoWriter::new(writer))?;
Ok(())
}
pub fn store_memory(pack: &Pack) -> Result<AlignedVec, Error> {
let mut buffer = AlignedVec::new();
store(pack, &mut buffer)?;
Ok(buffer)
}
pub fn store_file(
pack: &Pack,
path: &Path,
) -> Result<(), Error> {
let mut file = fs::File::create(path)?;
store(pack, &mut file)?;
file.sync_all()?;
drop(file);
Ok(())
}