evaltor 0.1.0

A tool for evaluating the evaluatees on benchmarks
Documentation
pub mod filter;
pub mod fuzz;

use filter::BenchFilter;
use rand::{SeedableRng, rngs::StdRng, seq::SliceRandom};
use std::{collections::HashSet, fs::read_dir, path::PathBuf};

fn search_cases(path: &PathBuf, format: &str) -> Vec<PathBuf> {
    let mut cases = Vec::new();
    for entry in read_dir(path).unwrap() {
        let path = entry.unwrap().path();
        if path.is_file() {
            if let Some(extension) = path.extension() {
                if extension.eq_ignore_ascii_case(format) {
                    cases.push(path);
                }
            }
        } else if path.is_dir() {
            let sub_cases = search_cases(&path, format);
            cases.extend(sub_cases);
        }
    }
    cases.sort();
    cases
        .into_iter()
        .map(|c| c.canonicalize().unwrap())
        .collect()
}

pub trait BenchIF {
    fn name(&self) -> String;

    fn cases(&self) -> Vec<PathBuf>;

    fn mount(&self) -> Vec<PathBuf>;
}

#[derive(Clone, Debug)]
pub struct Benchmark {
    name: String,
    path: PathBuf,
    format: String,
}

impl Benchmark {
    pub fn new(name: &str, path: &PathBuf, format: &str) -> Self {
        Self {
            name: name.to_string(),
            path: path.clone(),
            format: format.to_string(),
        }
    }
}

impl BenchIF for Benchmark {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn cases(&self) -> Vec<PathBuf> {
        search_cases(&self.path, &self.format)
    }

    fn mount(&self) -> Vec<PathBuf> {
        vec![self.path.clone()]
    }
}

#[derive(Default)]
pub struct MultiBenchmark {
    name: Option<String>,
    benchs: Vec<Box<dyn BenchIF>>,
    filter: Vec<Box<dyn BenchFilter>>,
}

impl MultiBenchmark {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn set_name(mut self, name: &str) -> Self {
        self.name = Some(name.to_string());
        self
    }

    pub fn add_filter(mut self, filter: impl BenchFilter + 'static) -> Self {
        self.filter.push(Box::new(filter));
        self
    }

    pub fn add(mut self, b: Box<dyn BenchIF>) -> Self {
        self.benchs.push(b);
        self
    }
}

impl BenchIF for MultiBenchmark {
    fn name(&self) -> String {
        if let Some(n) = &self.name {
            n.clone()
        } else {
            let name: Vec<_> = self.benchs.iter().map(|b| b.name()).collect();
            name.join("_")
        }
    }

    fn cases(&self) -> Vec<PathBuf> {
        let cases: Vec<PathBuf> = self.benchs.iter().flat_map(|b| b.cases()).collect();
        let mut seen_filenames = HashSet::new();
        let mut res = Vec::new();
        for case in cases {
            let filename = case.file_name().unwrap();
            if seen_filenames.insert(filename.to_owned()) {
                res.push(case);
            }
        }
        for f in self.filter.iter() {
            res = f.filter(res);
        }
        let mut rng = StdRng::seed_from_u64(0);
        res.shuffle(&mut rng);
        res
    }

    fn mount(&self) -> Vec<PathBuf> {
        let benchs: HashSet<PathBuf> = self.benchs.iter().flat_map(|b| b.mount()).collect();
        benchs.into_iter().collect()
    }
}