libwaj 0.4.1

The library to handle waj file, the pack format for web site.
Documentation
use crate::error::{BaseError, WajError, WajFormatError};

use super::common::{AllProperties, Comparator, Entry, FullBuilderTrait, RealBuilder};
use jbk::reader::Range;
use std::path::Path;

pub struct Waj {
    container: jbk::reader::Container,
    pub(crate) root_index: jbk::reader::Index,
    pub(crate) properties: AllProperties,
}

impl std::ops::Deref for Waj {
    type Target = jbk::reader::Container;
    fn deref(&self) -> &Self::Target {
        &self.container
    }
}

fn create_properties(
    container: &jbk::reader::Container,
    index: &jbk::reader::Index,
) -> Result<AllProperties, BaseError> {
    AllProperties::new(
        index.get_store(container.get_entry_storage())?,
        container.get_value_storage(),
    )
}

impl Waj {
    pub fn new<P: AsRef<Path>>(file: P) -> Result<Self, WajError> {
        let container = jbk::reader::Container::new(&file)?;
        let root_index = container
            .get_directory_pack()
            .get_index_from_name("waj_entries")?
            .ok_or(WajFormatError("No `waj_entries` in the archive"))?;
        let properties = create_properties(&container, &root_index)?;

        Ok(Self {
            container,
            root_index,
            properties,
        })
    }

    pub fn create_properties(
        &self,
        index: &jbk::reader::Index,
    ) -> Result<AllProperties, BaseError> {
        create_properties(&self.container, index)
    }

    pub fn get_entry<B>(&self, path: &str) -> Result<Entry<B::Entry>, WajError>
    where
        B: FullBuilderTrait,
    {
        let comparator = Comparator::new(&self.properties);
        let builder = RealBuilder::<B>::new(&self.properties);
        let current_range: jbk::EntryRange = (&self.root_index).into();
        let comparator = comparator.compare_with(path.as_bytes());
        match current_range.find(&comparator)? {
            None => Err(WajError::PathNotFound(format!("Cannot found entry {path}"))),
            Some(idx) => {
                let entry = current_range
                    .get_entry(&builder, idx)?
                    .expect("idx should be valid");
                Ok(entry)
            }
        }
    }
}