anthem 2.0.0

A command-line application for assisting in the verification of answer set programs
Documentation
use {
    either::Either,
    std::{ffi::OsStr, path::PathBuf},
    walkdir::WalkDir,
};

#[derive(Debug)]
pub struct Files {
    pub specifications: Vec<PathBuf>,
    pub programs: Vec<PathBuf>,
    pub user_guides: Vec<PathBuf>,
    pub proof_outlines: Vec<PathBuf>,
    pub other: Vec<PathBuf>,
}

impl Files {
    pub fn empty() -> Self {
        Files {
            specifications: vec![],
            programs: vec![],
            user_guides: vec![],
            proof_outlines: vec![],
            other: vec![],
        }
    }

    pub fn sort(paths: impl IntoIterator<Item = PathBuf>) -> Result<Self, walkdir::Error> {
        let mut result = Files::empty();

        for entry in paths
            .into_iter()
            .map(WalkDir::new)
            .flat_map(WalkDir::sort_by_file_name)
        {
            let entry = entry?;
            if entry.file_type().is_file() {
                let path = entry.into_path();
                match path.extension().and_then(OsStr::to_str) {
                    Some("lp") => &mut result.programs,
                    Some("spec") => &mut result.specifications,
                    Some("ug") => &mut result.user_guides,
                    Some("po") => &mut result.proof_outlines,
                    None | Some(_) => &mut result.other,
                }
                .push(path);
            }
        }

        Ok(result)
    }

    pub fn left(&self) -> Option<&PathBuf> {
        self.programs.first()
    }

    pub fn right(&self) -> Option<&PathBuf> {
        self.programs.get(1)
    }

    pub fn specification(&self) -> Option<Either<&PathBuf, &PathBuf>> {
        self.specifications
            .first()
            .map(Either::Right)
            .or_else(|| self.programs.first().map(Either::Left))
    }

    pub fn program(&self) -> Option<&PathBuf> {
        if self.specifications.is_empty() {
            self.programs.get(1)
        } else {
            self.programs.first()
        }
    }

    pub fn user_guide(&self) -> Option<&PathBuf> {
        self.user_guides.first()
    }

    pub fn proof_outline(&self) -> Option<&PathBuf> {
        self.proof_outlines.first()
    }
}