impl CommandGenerator {
pub fn generate(&self, count: usize) -> Vec<String> {
let mut commands = Vec::with_capacity(count);
let mut seen = HashSet::new();
let phases: Vec<Box<dyn Iterator<Item = String> + '_>> = vec![
Box::new(self.base_commands()),
Box::new(self.variant_commands()),
Box::new(self.flag_commands()),
Box::new(self.full_commands()),
];
for phase in phases {
for cmd in phase {
if commands.len() >= count {
break;
}
if seen.insert(cmd.clone()) {
commands.push(cmd);
}
}
}
commands.truncate(count);
commands
}
fn base_commands(&self) -> impl Iterator<Item = String> + '_ {
self.templates.iter().map(|t| t.base.to_string())
}
fn variant_commands(&self) -> impl Iterator<Item = String> + '_ {
self.templates.iter().flat_map(|t| {
t.variants
.iter()
.map(move |v| Self::build_command(t.base, v, "", ""))
})
}
fn flag_commands(&self) -> impl Iterator<Item = String> + '_ {
self.templates.iter().flat_map(|t| {
t.variants.iter().flat_map(move |v| {
t.flags
.iter()
.map(move |f| Self::build_command(t.base, v, f, ""))
})
})
}
fn full_commands(&self) -> impl Iterator<Item = String> + '_ {
self.templates.iter().flat_map(|t| {
t.variants.iter().flat_map(move |v| {
t.flags.iter().flat_map(move |f| {
t.args
.iter()
.map(move |a| Self::build_command(t.base, v, f, a))
})
})
})
}
fn build_command(base: &str, variant: &str, flag: &str, arg: &str) -> String {
let mut cmd = base.to_string();
for part in [variant, flag, arg] {
if !part.is_empty() {
cmd.push(' ');
cmd.push_str(part);
}
}
cmd
}
}