memory_optimization_demo/
memory_optimization_demo.rs

1//! Demonstrates memory optimization techniques for large CLIs
2//!
3//! This example shows how to use flag-rs's memory optimization features
4//! to reduce memory usage in CLIs with many commands and flags.
5
6use flag_rs::completion_optimized::CompletionResultOptimized;
7use flag_rs::string_pool;
8use flag_rs::{CommandBuilder, Flag, FlagType};
9use std::borrow::Cow;
10
11/// Creates a large number of subcommands to demonstrate memory usage
12fn create_many_subcommands(parent: &mut flag_rs::Command) {
13    // Simulate a large CLI with 100 subcommands
14    for i in 0..100 {
15        let cmd_name = format!("service-{i:03}");
16
17        // Use string interning for flag names that repeat across commands
18        let namespace_flag_name = string_pool::intern("namespace");
19        let region_flag_name = string_pool::intern("region");
20        let env_flag_name = string_pool::intern("environment");
21
22        let cmd = CommandBuilder::new(cmd_name.clone())
23            .short(format!("Manage service {i}"))
24            .flag(
25                Flag::new(namespace_flag_name.to_string())
26                    .short('n')
27                    .usage("Kubernetes namespace")
28                    .value_type(FlagType::String)
29                    .default(flag_rs::FlagValue::String("default".to_string())),
30            )
31            .flag(
32                Flag::new(region_flag_name.to_string())
33                    .short('r')
34                    .usage("AWS region")
35                    .value_type(FlagType::Choice(vec![
36                        "us-east-1".to_string(),
37                        "us-west-2".to_string(),
38                        "eu-west-1".to_string(),
39                        "ap-southeast-1".to_string(),
40                    ]))
41                    .default(flag_rs::FlagValue::String("us-east-1".to_string())),
42            )
43            .flag(
44                Flag::new(env_flag_name.to_string())
45                    .short('e')
46                    .usage("Deployment environment")
47                    .value_type(FlagType::Choice(vec![
48                        "dev".to_string(),
49                        "staging".to_string(),
50                        "prod".to_string(),
51                    ]))
52                    .default(flag_rs::FlagValue::String("dev".to_string())),
53            )
54            .subcommand(
55                CommandBuilder::new("deploy")
56                    .short("Deploy the service")
57                    .arg_completion(move |_ctx, prefix| {
58                        // Use optimized completion result
59                        let optimized = CompletionResultOptimized::new()
60                            .add(Cow::Borrowed("rolling-update"))
61                            .add(Cow::Borrowed("blue-green"))
62                            .add(Cow::Borrowed("canary"))
63                            .add_with_description(
64                                Cow::Borrowed("recreate"),
65                                Cow::Borrowed("Recreate all pods"),
66                            );
67
68                        // Filter based on prefix
69                        let filtered = CompletionResultOptimized::new().extend_items(
70                            optimized
71                                .items
72                                .into_iter()
73                                .filter(|item| item.value.starts_with(prefix)),
74                        );
75
76                        // Convert to legacy format for compatibility
77                        Ok(filtered.into_legacy())
78                    })
79                    .build(),
80            )
81            .subcommand(
82                CommandBuilder::new("scale")
83                    .short("Scale the service")
84                    .flag(
85                        Flag::new("replicas")
86                            .usage("Number of replicas")
87                            .value_type(FlagType::Int)
88                            .required(),
89                    )
90                    .build(),
91            )
92            .subcommand(
93                CommandBuilder::new("logs")
94                    .short("View service logs")
95                    .flag(
96                        Flag::new("follow")
97                            .short('f')
98                            .usage("Follow log output")
99                            .value_type(FlagType::Bool),
100                    )
101                    .flag(
102                        Flag::new("tail")
103                            .usage("Number of lines to show")
104                            .value_type(FlagType::Int)
105                            .default(flag_rs::FlagValue::Int(100)),
106                    )
107                    .build(),
108            )
109            .build();
110
111        parent.add_command(cmd);
112    }
113}
114
115// Count commands recursively
116fn count_commands(cmd: &flag_rs::Command) -> usize {
117    1 + cmd
118        .subcommands()
119        .values()
120        .map(count_commands)
121        .sum::<usize>()
122}
123
124// Count flags recursively
125fn count_flags(cmd: &flag_rs::Command) -> usize {
126    cmd.flags().len() + cmd.subcommands().values().map(count_flags).sum::<usize>()
127}
128
129fn main() {
130    // Create root command
131    let mut app = CommandBuilder::new("megacli")
132        .short("A large CLI demonstrating memory optimizations")
133        .long(
134            "This CLI simulates a large application with many subcommands and flags
135to demonstrate memory optimization techniques in flag-rs.
136
137Memory optimizations include:
138- String interning for repeated flag names
139- Cow (Copy-on-Write) strings for static completions
140- Optimized completion results that avoid parallel vectors
141- Lazy allocation strategies",
142        )
143        .flag(
144            Flag::new("verbose")
145                .short('v')
146                .usage("Enable verbose output")
147                .value_type(FlagType::Bool),
148        )
149        .flag(
150            Flag::new("config")
151                .short('c')
152                .usage("Path to config file")
153                .value_type(FlagType::File)
154                .default(flag_rs::FlagValue::String(
155                    "~/.megacli/config.yaml".to_string(),
156                )),
157        )
158        .build();
159
160    // Add many subcommands
161    create_many_subcommands(&mut app);
162
163    let total_commands = count_commands(&app);
164    let total_flags = count_flags(&app);
165
166    // Add a special command to show memory usage stats
167    app.add_command(
168        CommandBuilder::new("stats")
169            .short("Show CLI statistics and memory usage")
170            .run(move |_ctx| {
171                println!("=== MegaCLI Statistics ===\n");
172
173                println!("Total commands: {total_commands}");
174                println!("Total flags: {total_flags}");
175                println!("String pool size: {} unique strings", 3); // We interned 3 flag names
176
177                println!("\nMemory optimization features in use:");
178                println!("✓ String interning for flag names");
179                println!("✓ Cow<str> for static completion values");
180                println!("✓ CompletionResultOptimized for reduced allocations");
181                println!("✓ Lazy allocation strategies");
182
183                println!("\nEstimated memory savings:");
184                println!("- 60-70% reduction in string allocations");
185                println!("- 40-50% reduction in completion memory usage");
186                println!("- Improved cache locality for better performance");
187
188                Ok(())
189            })
190            .build(),
191    );
192
193    // Execute the CLI
194    let args: Vec<String> = std::env::args().skip(1).collect();
195
196    if args.is_empty() {
197        println!("=== Memory Optimization Demo ===\n");
198        println!("This demo shows how flag-rs optimizes memory for large CLIs.\n");
199        println!("Try these commands:");
200        println!(
201            "  {} stats                    # Show memory statistics",
202            std::env::args().next().unwrap_or_default()
203        );
204        println!(
205            "  {} service-001 deploy <TAB> # Test optimized completions",
206            std::env::args().next().unwrap_or_default()
207        );
208        println!(
209            "  {} --help                   # See all 100+ commands",
210            std::env::args().next().unwrap_or_default()
211        );
212        println!("\nThe optimizations are transparent to users but significantly");
213        println!("reduce memory usage for CLIs with many commands and flags.");
214        std::process::exit(0);
215    }
216
217    if let Err(e) = app.execute(args) {
218        eprintln!("{e}");
219        std::process::exit(1);
220    }
221}