struct_audit/
cli.rs

1use clap::{Parser, Subcommand, ValueEnum};
2use std::path::PathBuf;
3
4#[derive(Parser)]
5#[command(name = "struct-audit")]
6#[command(
7    author,
8    version,
9    about = "Analyze binary memory layouts to detect padding inefficiencies"
10)]
11#[command(
12    long_about = "struct-audit parses DWARF debugging information to visualize the physical \
13layout of data structures, detect padding holes, and analyze cache line efficiency.\n\n\
14Example:\n  struct-audit inspect ./target/debug/myapp --filter MyStruct"
15)]
16pub struct Cli {
17    #[command(subcommand)]
18    pub command: Commands,
19}
20
21#[derive(Subcommand)]
22pub enum Commands {
23    /// Analyze and display struct layouts from a binary
24    Inspect {
25        /// Path to the binary file to analyze
26        #[arg(value_name = "BINARY")]
27        binary: PathBuf,
28
29        /// Filter structs by name (substring match)
30        #[arg(short, long)]
31        filter: Option<String>,
32
33        /// Output format
34        #[arg(short, long, value_enum, default_value = "table")]
35        output: OutputFormat,
36
37        /// Sort structs by field
38        #[arg(short, long, value_enum, default_value = "name")]
39        sort_by: SortField,
40
41        /// Show only the top N structs (by sort order)
42        #[arg(short = 'n', long)]
43        top: Option<usize>,
44
45        /// Show only structs with at least N bytes of padding
46        #[arg(long)]
47        min_padding: Option<u64>,
48
49        /// Disable colored output
50        #[arg(long)]
51        no_color: bool,
52
53        /// Cache line size in bytes (must be > 0)
54        #[arg(long, default_value = "64", value_parser = clap::value_parser!(u32).range(1..))]
55        cache_line: u32,
56
57        /// Pretty-print JSON output
58        #[arg(long)]
59        pretty: bool,
60    },
61
62    /// Compare struct layouts between two binaries
63    Diff {
64        /// Path to the old (baseline) binary
65        #[arg(value_name = "OLD")]
66        old: PathBuf,
67
68        /// Path to the new binary
69        #[arg(value_name = "NEW")]
70        new: PathBuf,
71
72        /// Filter structs by name (substring match)
73        #[arg(short, long)]
74        filter: Option<String>,
75
76        /// Output format
77        #[arg(short, long, value_enum, default_value = "table")]
78        output: OutputFormat,
79
80        /// Cache line size in bytes (must be > 0)
81        #[arg(long, default_value = "64", value_parser = clap::value_parser!(u32).range(1..))]
82        cache_line: u32,
83
84        /// Exit with error code 1 if any regressions found (size or padding increased)
85        #[arg(long)]
86        fail_on_regression: bool,
87    },
88
89    /// Check struct layouts against budget constraints
90    Check {
91        /// Path to the binary file to analyze
92        #[arg(value_name = "BINARY")]
93        binary: PathBuf,
94
95        /// Path to config file (.struct-audit.yaml)
96        #[arg(short, long, default_value = ".struct-audit.yaml")]
97        config: PathBuf,
98
99        /// Cache line size in bytes (must be > 0)
100        #[arg(long, default_value = "64", value_parser = clap::value_parser!(u32).range(1..))]
101        cache_line: u32,
102    },
103}
104
105#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
106pub enum OutputFormat {
107    Table,
108    Json,
109}
110
111#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
112pub enum SortField {
113    /// Sort by struct name (alphabetical)
114    Name,
115    /// Sort by total size (largest first)
116    Size,
117    /// Sort by padding bytes (most padding first)
118    Padding,
119    /// Sort by padding percentage (worst efficiency first)
120    PaddingPct,
121}