derive_show_asm/
derive_show_asm.rs

1//! Parsing snippet from cargo-show-asm
2//! Derive + typed fallback + external both with and without name
3
4use bpaf::{construct, long, Bpaf, Parser, ShellComp};
5use std::{convert::Infallible, path::PathBuf};
6
7#[derive(Clone, Debug, Bpaf)]
8#[bpaf(options("asm"))] // derives cargo helper for cargo-asm
9#[allow(clippy::struct_excessive_bools)]
10pub struct Options {
11    #[bpaf(external(parse_manifest_path))]
12    pub manifest_path: PathBuf,
13    /// Custom target directory for generated artifacts
14    #[bpaf(argument("DIR"))]
15    pub target_dir: Option<PathBuf>,
16    /// Package to use if ambigous
17    #[bpaf(long, short, argument("SPEC"))]
18    pub package: Option<String>,
19    #[bpaf(external, optional)]
20    pub focus: Option<Focus>,
21    /// Produce a build plan instead of actually building
22    pub dry: bool,
23    /// Requires Cargo.lock and cache are up to date
24    pub frozen: bool,
25    /// Requires Cargo.lock is up to date
26    pub locked: bool,
27    /// Run without accessing the network
28    pub offline: bool,
29    #[bpaf(external)]
30    pub format: Format,
31    #[bpaf(external, fallback(Syntax::Intel))]
32    pub syntax: Syntax,
33    #[bpaf(external)]
34    pub selected_function: SelectedFunction,
35}
36
37#[derive(Debug, Clone, Bpaf)]
38/// Item to pick from the output
39pub struct SelectedFunction {
40    /// Complete or partial function name to filter
41    #[bpaf(positional("FUNCTION"))]
42    pub function: Option<String>,
43    /// Select nth item from a filtered list
44    #[bpaf(positional("INDEX"), fallback(0))]
45    pub nth: usize,
46}
47
48fn parse_manifest_path() -> impl Parser<PathBuf> {
49    long("manifest-path")
50        .help("Path to Cargo.toml")
51        .argument::<PathBuf>("PATH")
52        .complete_shell(ShellComp::File {
53            mask: Some("*.toml"),
54        })
55        .parse(|p| {
56            // cargo-metadata wants to see
57            if p.is_absolute() {
58                Ok(p)
59            } else {
60                std::env::current_dir()
61                    .map(|d| d.join(p))
62                    .and_then(|full_path| full_path.canonicalize())
63            }
64        })
65        .fallback_with(|| std::env::current_dir().map(|x| x.join("Cargo.toml")))
66}
67
68#[derive(Debug, Clone, Bpaf)]
69/// How to render output
70pub struct Format {
71    /// Print interleaved Rust code
72    pub rust: bool,
73
74    #[bpaf(external(color_detection))]
75    pub color: bool,
76
77    /// include full demangled name instead of just prefix
78    pub full_name: bool,
79}
80
81#[derive(Debug, Clone, Bpaf)]
82/// Pick output type
83///
84/// included help
85///
86///
87/// Extended help
88pub enum Syntax {
89    /// Generate assembly using Intel style
90    Intel,
91    /// Generate assembly using AT&T style
92    Att,
93}
94
95fn color_detection() -> impl Parser<bool> {
96    let yes = long("color")
97        .help("Enable color highlighting")
98        .req_flag(true);
99    let no = long("no-color")
100        .help("Disable color highlighting")
101        .req_flag(false);
102    construct!([yes, no]).fallback_with::<_, Infallible>(|| {
103        // we can call for supports-color crate here
104        Ok(true)
105    })
106}
107
108fn comp_examples(prefix: &String) -> Vec<(String, Option<String>)> {
109    // in the actual app we can ask cargo-metadata for this info
110    let examples = ["derive_show_asm", "coreutils", "comonad"];
111    examples
112        .iter()
113        .filter_map(|e| {
114            if e.starts_with(prefix) {
115                Some((e.to_string(), None))
116            } else {
117                None
118            }
119        })
120        .collect()
121}
122
123#[derive(Debug, Clone, Bpaf)]
124/// Select artifact to use for analysis
125///
126/// Only one is valid
127pub enum Focus {
128    /// Show results from library code
129    Lib,
130
131    Test(
132        /// Show results from a test
133        #[bpaf(long("test"), argument("TEST"))]
134        String,
135    ),
136
137    Bench(
138        /// Show results from a benchmark
139        #[bpaf(long("bench"), argument("BENCH"))]
140        String,
141    ),
142
143    Example(
144        /// Show results from an example
145        #[bpaf(long("example"), argument("EXAMPLE"), complete(comp_examples))]
146        String,
147    ),
148
149    Bin(
150        /// Show results from a binary
151        #[bpaf(long("bin"), argument("BIN"))]
152        String,
153    ),
154}
155
156fn main() {
157    println!("{:#?}", options().run());
158}