router-eval 0.1.1

Evaluation tooling for SteadyMux routing policy.
Documentation
// SPDX-License-Identifier: AGPL-3.0-or-later

#![forbid(unsafe_code)]

use router_eval::MAX_EVALUATION_CORPUS_BYTES;
use router_eval::evaluate_corpus;
use std::fs::File;
use std::io::Read;
use std::process::ExitCode;

const DEFAULT_CORPUS: &[u8] =
    include_bytes!("../../../tests/fixtures/evaluation/m2-policy-corpus.json");

fn main() -> ExitCode {
    let mut args = std::env::args_os();
    let _program = args.next();
    let bytes = match (args.next(), args.next()) {
        (None, None) => DEFAULT_CORPUS.to_vec(),
        (Some(path), None) => match read_bounded(path) {
            Ok(bytes) => bytes,
            Err(_) => {
                eprintln!("router-eval: corpus could not be read");
                return ExitCode::from(2);
            }
        },
        _ => {
            eprintln!("usage: router-eval [CORPUS.json]");
            return ExitCode::from(2);
        }
    };

    let report = match evaluate_corpus(&bytes) {
        Ok(report) => report,
        Err(error) => {
            eprintln!("router-eval: {error}");
            return ExitCode::from(1);
        }
    };
    match serde_json::to_string_pretty(&report) {
        Ok(json) => println!("{json}"),
        Err(_) => {
            eprintln!("router-eval: report serialization failed");
            return ExitCode::from(1);
        }
    }
    if report.thresholds_passed {
        ExitCode::SUCCESS
    } else {
        ExitCode::from(1)
    }
}

fn read_bounded(path: std::ffi::OsString) -> Result<Vec<u8>, std::io::Error> {
    let file = File::open(path)?;
    let mut bytes = Vec::new();
    file.take((MAX_EVALUATION_CORPUS_BYTES + 1) as u64)
        .read_to_end(&mut bytes)?;
    if bytes.len() > MAX_EVALUATION_CORPUS_BYTES {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "corpus exceeds the fixed input limit",
        ));
    }
    Ok(bytes)
}