ignis 0.1.0

A library for editing various 3DSFE formats.
Documentation
use anyhow::{anyhow, Result};
use std::fs::{create_dir_all, OpenOptions};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

pub trait FilesystemLayer {
    fn exists(&self, filename: &str) -> bool;

    fn open(&self, filename: &str) -> Result<Vec<u8>>;

    fn save(&self, filename: &str, bytes: &[u8]) -> Result<()>;
}

pub struct DirectoryFilesystemLayer {
    directory_path_str: String,
}

impl DirectoryFilesystemLayer {
    pub fn new(directory_path_str: &str) -> Result<Self> {
        let directory_path = Path::new(directory_path_str);
        if !(directory_path.exists() && directory_path.is_dir()) {
            return Err(anyhow!(
                "Path {} is not an existing directory",
                directory_path_str
            ));
        }

        Ok(DirectoryFilesystemLayer {
            directory_path_str: directory_path_str.to_string(),
        })
    }

    fn create_path(&self, filename: &str) -> PathBuf {
        let mut full_path = PathBuf::new();
        full_path.push(&self.directory_path_str);
        full_path.push(filename);
        full_path
    }
}

impl FilesystemLayer for DirectoryFilesystemLayer {
    fn exists(&self, filename: &str) -> bool {
        let directory_path = self.create_path(filename);
        directory_path.exists()
    }

    fn open(&self, filename: &str) -> Result<Vec<u8>> {
        let path = self.create_path(filename);
        let path = path
            .to_str()
            .ok_or(anyhow!("Error creating full path in directory provider"))?;
        let mut file = OpenOptions::new().read(true).open(path)?;
        let mut file_contents: Vec<u8> = Vec::new();
        file.read_to_end(&mut file_contents)?;
        Ok(file_contents)
    }

    fn save(&self, filename: &str, bytes: &[u8]) -> Result<()> {
        let path = self.create_path(filename);
        let parent = path.parent()
            .ok_or(anyhow!("Error finding parent of path given in save"))?
            .to_str()
            .ok_or(anyhow!("Error creating full path in directory provider"))?;
        let path = path
            .to_str()
            .ok_or(anyhow!("Error creating full path in directory provider"))?;

        create_dir_all(&parent)?;
        let mut file = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(&path)?;
        file.write_all(bytes)?;
        Ok(())
    }
}