confiner 0.2.1

A config language for things that look like trees.
Documentation
use super::*;

struct IncludeError
{
    path:  PathBuf,
    inner: StdError
}

impl std::fmt::Debug for IncludeError
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
    {
        write!(f, "While including path: {:?}", self.path)
    }
}

impl std::fmt::Display for IncludeError
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
    {
        <Self as std::fmt::Debug>::fmt(self, f)
    }
}

impl std::error::Error for IncludeError
{
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)>
    {
        Some(self.inner.as_ref())
    }
}

#[derive(Default)]
pub struct FileLoader
{
    loader:  Loader,
    visited: HashSet<PathBuf>
}

impl FileLoader
{
    pub fn load(&mut self, path: impl AsRef<Path>) -> StdResult
    {
        self.load_single(path)?;

        loop
        {
            let to_include = self.loader
                .to_include()
                .difference(&self.visited)
                .cloned()
                .collect::<HashSet<PathBuf>>();

            if to_include.len() == 0
            {
                break;
            }

            for path in to_include
            {
                self.load_single(&path)
                    .map_err(|inner| IncludeError {
                        path: path.to_owned(), inner
                    })?;
            }
        }

        Ok(())
    }

    fn load_single(&mut self, path_ref: impl AsRef<Path>) -> StdResult
    {
        let path = path_ref.as_ref().canonicalize()?;
        let to_load = std::fs::read_to_string(&path)?;
        let dir = path.parent().expect("Expected file path to have parent");

        self.loader.add_document(&to_load, &dir)?;
        self.visited.insert(path.to_owned());

        Ok(())
    }

    pub fn inner(&self) -> &Loader { &self.loader }

    pub fn into_inner(self) -> Loader { self.loader }
}