Skip to main content

forge/compare_matrix/
mod.rs

1//! All-spec `WoW` Lab versus `SimulationCraft` comparison matrix.
2
3mod report;
4mod runner;
5mod types;
6
7use anyhow::{Result, anyhow, ensure};
8use clap::Args;
9use wowlab_types::game::SpecId;
10
11use self::types::MatrixFormat;
12use crate::run::{FightDurationSeconds, IterationCount, RunParameters, RunParametersError};
13
14const DEFAULT_DURATION_SECS: u32 = 300;
15const DEFAULT_ITERATIONS: u32 = 1;
16const DEFAULT_JOBS: usize = 4;
17
18#[derive(Args, Debug)]
19pub(crate) struct CompareMatrixArgs {
20    /// Optional spec slugs. Omit to compare every supported spec.
21    #[arg(value_name = "SPEC")]
22    pub(crate) specs: Vec<Box<str>>,
23
24    /// Fight duration in seconds.
25    #[arg(long, default_value_t = DEFAULT_DURATION_SECS)]
26    pub(crate) duration: u32,
27
28    /// Number of iterations per provider and spec.
29    #[arg(long, default_value_t = DEFAULT_ITERATIONS)]
30    pub(crate) iterations: u32,
31
32    /// Maximum number of specs compared concurrently.
33    #[arg(long, short = 'j', default_value_t = DEFAULT_JOBS)]
34    pub(crate) jobs: usize,
35
36    /// Player race override applied to every spec.
37    #[arg(long)]
38    pub(crate) race: Option<String>,
39
40    /// Output format.
41    #[arg(long, value_enum, default_value_t = MatrixFormat::Table)]
42    pub(crate) format: MatrixFormat,
43}
44
45impl TryFrom<&CompareMatrixArgs> for RunParameters {
46    type Error = RunParametersError;
47
48    fn try_from(args: &CompareMatrixArgs) -> Result<Self, Self::Error> {
49        let fight_duration = FightDurationSeconds::try_from(args.duration)?;
50        let iterations = IterationCount::try_from(args.iterations)?;
51
52        Ok(Self::new(iterations, fight_duration))
53    }
54}
55
56pub(crate) fn run(args: &CompareMatrixArgs) -> Result<()> {
57    let parameters = RunParameters::try_from(args)?;
58
59    ensure!(args.jobs > 0, "jobs must be greater than zero");
60
61    let filter = args
62        .specs
63        .iter()
64        .map(|slug| {
65            SpecId::from_manifest_slug(slug).ok_or_else(|| anyhow!("unknown spec slug: {slug}"))
66        })
67        .collect::<Result<Vec<_>>>()?;
68    let matrix = runner::run(&filter, parameters, args.jobs, args.race.clone())?;
69
70    report::print(&matrix, args.format)
71}