rdss 0.2.1

Rust Data Storage System
Documentation
use std::{
    collections::HashMap,
    io::{BufReader, Seek},
    path::PathBuf,
};
use thiserror::Error;

use crate::{read, Binary, BinaryError, Format};

#[derive(Debug, Error)]
pub enum LoaderError {
    #[error("The specified binary path does not exist: {0}")]
    BinaryDoesNotExist(PathBuf),
    #[error("The binary file is missing or malformed: {0}")]
    FileNotFound(String),
    #[error("Failed to deserialize the binary format: {0}")]
    DeserializationFailed(#[from] BinaryError),
    #[error("Failed to read the binary file: {0}")]
    ReadError(#[from] std::io::Error),
}

pub struct Loader {
    binary: PathBuf,
    files: HashMap<String, (u64, u64)>,
    start: u64,
}

impl Loader {
    pub fn new(binary: impl Into<PathBuf>) -> Self {
        Loader {
            binary: binary.into(),
            files: HashMap::new(),
            start: 0,
        }
    }

    pub fn files(&self) -> Vec<String> {
        self.files.iter().map(|file| file.0.clone()).collect()
    }

    pub fn load(&mut self) -> Result<(), LoaderError> {
        if !self.binary.exists() {
            return Err(LoaderError::BinaryDoesNotExist(self.binary.clone()));
        }
        let file = std::fs::File::open(&self.binary)
            .map_err(|_| LoaderError::BinaryDoesNotExist(self.binary.clone()))?;
        let mut reader = BufReader::new(file);

        let format =
            Format::deserialize(&mut reader).map_err(LoaderError::DeserializationFailed)?;

        for file in format.files {
            self.files
                .insert(file.path.clone(), (file.offset, file.size));
        }

        self.start = reader.stream_position().map_err(LoaderError::ReadError)?;

        Ok(())
    }

    pub fn read_raw(&mut self, path: &str) -> Result<Vec<u8>, LoaderError> {
        if let Some((offset, size)) = self.files.get(path) {
            let file = std::fs::File::open(&self.binary)
                .map_err(|_| LoaderError::BinaryDoesNotExist(self.binary.clone()))?;
            let mut reader = BufReader::new(file);

            read::skip(&mut reader, self.start + offset).map_err(LoaderError::ReadError)?;
            let mut buffer = vec![0; *size as usize];
            read::exact(&mut reader, &mut buffer).map_err(LoaderError::ReadError)?;
            Ok(buffer)
        } else {
            Err(LoaderError::FileNotFound(path.to_string()))
        }
    }

    pub fn read(&mut self, path: &str) -> Result<String, LoaderError> {
        let bytes = self.read_raw(path)?;
        String::from_utf8(bytes.into()).map_err(|e| {
            LoaderError::ReadError(std::io::Error::new(std::io::ErrorKind::InvalidData, e))
        })
    }
}