wowlab_engine/cli/
args.rs1use clap::{Parser, Subcommand, ValueEnum};
2use wowlab_common::sim::defaults::DEFAULT_ITERATIONS;
3use wowlab_fs::path::PathBuf;
4use wowlab_types::{constants::DEFAULT_DURATION_S, game::SpecId};
5
6#[derive(Debug, Parser)]
7#[command(name = "wowlab-engine")]
8#[command(about = "WoW Lab Simulation Engine")]
9pub(super) struct Args {
10 #[arg(long, short, global = true)]
12 pub quiet: bool,
13
14 #[command(subcommand)]
15 pub command: Command,
16}
17
18#[derive(Debug, Subcommand)]
19#[non_exhaustive]
20pub(super) enum Command {
21 Sim {
23 #[arg(short, long, value_parser = parse_spec)]
25 spec: SpecId,
26
27 #[arg(short, long, default_value_t = DEFAULT_DURATION_S)]
29 duration: f64,
30
31 #[arg(short, long, default_value_t = DEFAULT_ITERATIONS)]
33 iterations: u32,
34
35 #[arg(long)]
37 threads: Option<usize>,
38
39 #[arg(long)]
41 seed: Option<u64>,
42
43 #[arg(short = 'f', long, default_value_t)]
45 format: OutputFormat,
46
47 #[arg(long)]
49 rotation: Option<PathBuf>,
50 },
51
52 Validate {
54 #[arg(short, long)]
56 rotation: PathBuf,
57
58 #[arg(short, long, value_parser = parse_spec)]
60 spec: Option<SpecId>,
61 },
62
63 Inspect {
65 #[arg(short, long, value_parser = parse_spec)]
67 spec: SpecId,
68
69 #[arg(short = 'f', long, default_value_t)]
71 format: OutputFormat,
72
73 #[arg(long)]
75 id: Option<u32>,
76 },
77
78 Audit {
80 #[arg(short, long)]
82 manifests: Option<PathBuf>,
83 },
84
85 Version,
87}
88
89fn parse_spec(s: &str) -> Result<SpecId, String> {
91 SpecId::from_manifest_slug(s).ok_or_else(|| {
92 format!(
93 "unknown spec '{}'. valid specs:\n {}",
94 s,
95 valid_spec_slugs_for_error().join("\n ")
96 )
97 })
98}
99
100fn valid_spec_slugs_for_error() -> Vec<&'static str> {
101 use strum::IntoEnumIterator;
102 let mut slugs: Vec<&str> = SpecId::iter()
103 .filter(|s| s.is_dps())
104 .map(SpecId::slug)
105 .collect();
106
107 slugs.sort_unstable();
108
109 slugs
110}
111
112#[derive(Clone, Copy, Debug, Default, ValueEnum)]
113#[non_exhaustive]
114pub(super) enum OutputFormat {
115 #[default]
116 Text,
117 Json,
118}
119
120impl std::fmt::Display for OutputFormat {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 let s = match self {
123 Self::Text => "text",
124 Self::Json => "json",
125 };
126
127 f.write_str(s)
128 }
129}