use bpaf::{construct, long, short, Bpaf, Parser};
use std::path::PathBuf;
#[derive(Clone, Debug, Bpaf)]
#[bpaf(options("asm"))]
#[allow(clippy::struct_excessive_bools)]
pub struct Options {
#[bpaf(external(parse_manifest_path))]
pub manifest_path: PathBuf,
#[bpaf(argument("DIR"))]
pub target_dir: Option<PathBuf>,
#[bpaf(long, short, argument("SPEC"))]
pub package: Option<String>,
#[bpaf(external, optional)]
pub focus: Option<Focus>,
pub dry: bool,
pub frozen: bool,
pub locked: bool,
pub offline: bool,
#[bpaf(external)]
pub format: Format,
#[bpaf(external)]
pub verbosity: usize,
#[bpaf(external, fallback(Syntax::Intel))]
pub syntax: Syntax,
#[bpaf(positional("FUNCTION"))]
pub function: Option<String>,
#[bpaf(positional("INDEX"), fallback(0))]
pub nth: usize,
}
fn verbosity() -> impl Parser<usize> {
short('v')
.long("verbose")
.help("more verbose output, can be specified multiple times")
.req_flag(())
.many()
.map(|v| v.len())
}
fn parse_manifest_path() -> impl Parser<PathBuf> {
long("manifest-path")
.help("Path to Cargo.toml")
.argument::<PathBuf>("PATH")
.parse(|p| {
if p.is_absolute() {
Ok(p)
} else {
std::env::current_dir()
.map(|d| d.join(p))
.and_then(|full_path| full_path.canonicalize())
}
})
.fallback_with(|| std::env::current_dir().map(|x| x.join("Cargo.toml")))
}
#[derive(Debug, Clone, Bpaf)]
pub struct Format {
pub rust: bool,
#[bpaf(external(color_detection))]
pub color: bool,
pub full_name: bool,
}
#[derive(Debug, Clone, Bpaf)]
pub enum Syntax {
Intel,
Att,
}
impl ToString for Syntax {
fn to_string(&self) -> String {
match self {
Syntax::Intel => String::from("llvm-args=-x86-asm-syntax=intel"),
Syntax::Att => String::from("llvm-args=-x86-asm-syntax=att"),
}
}
}
fn color_detection() -> impl Parser<bool> {
let yes = long("color")
.help("Enable color highlighting")
.req_flag(true);
let no = long("no-color")
.help("Disable color highlighting")
.req_flag(false);
construct!([yes, no]).fallback_with::<_, &str>(|| Ok(true))
}
#[derive(Debug, Clone, Bpaf)]
pub enum Focus {
Lib,
Test(
#[bpaf(long("test"), argument("TEST"))]
String,
),
Bench(
#[bpaf(long("bench"), argument("BENCH"))]
String,
),
Example(
#[bpaf(long("example"), argument("EXAMPLE"))]
String,
),
Bin(
#[bpaf(long("bin"), argument("BIN"))]
String,
),
}
impl std::fmt::Display for Focus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Focus::Lib => f.write_str("--lib"),
Focus::Test(t) => write!(f, "--test {}", t),
Focus::Bench(b) => write!(f, "--bench {}", b),
Focus::Example(e) => write!(f, "--example {}", e),
Focus::Bin(b) => write!(f, "--bin {}", b),
}
}
}
fn main() {
println!("{:#?}", options().run());
}