cmd_args/
group.rs

1use std::rc::Rc;
2use crate::{option, arg};
3use std::collections::HashMap;
4
5/// Consumer for the parsed result (arguments and options).
6type ParserResultConsumer = Box<dyn Fn(&Vec<arg::Value>, &HashMap<&str, option::Value>)>;
7
8/// A group is a collection of possible CLI options and arguments.
9/// Essentially it provides the context of a action called via CLI.
10/// For example: When calling something like `dummy.exe test --flag`
11/// then `test` is the command context since the action `test` should be invoked.
12/// Now `--flag` can now be either created on the `Root` group or
13/// the `test` group.
14/// When options are defined on the root group, they are available to every
15/// child group as well, while options defined on a child group are only available to the
16/// child group and its children.
17pub struct Group {
18    /// Descriptors for all anticipated options.
19    options: Option<HashMap<Rc<String>, Rc<option::Descriptor>>>,
20
21    /// Descriptors for all anticipated arguments.
22    arguments: Vec<arg::Descriptor>,
23
24    /// Child groups.
25    children: HashMap<Rc<String>, Rc<Group>>,
26
27    /// Lookup of child groups by known aliases (including name).
28    children_lookup: HashMap<Rc<String>, Rc<Group>>,
29
30    /// Lookup of aliases by group name.
31    alias_lookup: HashMap<Rc<String>, Vec<Rc<String>>>,
32
33    /// Consumer called with the parsed options and arguments for this group.
34    consumer: ParserResultConsumer,
35
36    /// Description of the group.
37    description: String,
38}
39
40impl Group {
41    /// Create new group configuration.
42    pub fn new(consumer: ParserResultConsumer, description: &str) -> Self {
43        Group {
44            options: Some(HashMap::new()),
45            arguments: Vec::new(),
46            children: HashMap::new(),
47            children_lookup: HashMap::new(),
48            alias_lookup: HashMap::new(),
49            consumer,
50            description: String::from(description),
51        }
52    }
53
54    /// Add an argument to this group.
55    pub fn add_argument(mut self, argument: arg::Descriptor) -> Self {
56        self.arguments.push(argument);
57
58        self
59    }
60
61    /// Get argument descriptors.
62    pub fn get_arguments(&self) -> &Vec<arg::Descriptor> {
63        &self.arguments
64    }
65
66    /// Add an option to this group.
67    pub fn add_option(mut self, option: option::Descriptor) -> Self {
68        assert!(!&self.options.as_ref().unwrap().contains_key(option.name()));
69
70        self.options.as_mut().unwrap().insert(option.take_name(), Rc::new(option));
71
72        self
73    }
74
75    /// Take ownership of all specified options.
76    pub fn get_options(&self) -> &HashMap<Rc<String>, Rc<option::Descriptor>> {
77        self.options.as_ref().unwrap()
78    }
79
80    /// Add a child group known by the passed name.
81    pub fn add_child(mut self, name: &str, aliases: Option<Vec<&str>>, group: Group) -> Self {
82        let name = Rc::new(String::from(name));
83        let group = Rc::new(group);
84
85        assert!(!self.children.contains_key(&name));
86        self.children.insert(Rc::clone(&name), Rc::clone(&group));
87
88        // Insert aliases in lookup
89        assert!(!self.children_lookup.contains_key(&name));
90        self.children_lookup.insert(Rc::clone(&name), Rc::clone(&group));
91
92        if aliases.is_some() {
93            let aliases = aliases.unwrap();
94            let mut alias_vec = Vec::with_capacity(aliases.len());
95            for alias in aliases {
96                let alias = Rc::new(String::from(alias));
97                alias_vec.push(Rc::clone(&alias));
98
99                assert!(!self.children_lookup.contains_key(&alias));
100                self.children_lookup.insert(Rc::clone(&alias), Rc::clone(&group));
101            }
102
103            self.alias_lookup.insert(Rc::clone(&name), alias_vec);
104        }
105
106        self
107    }
108
109    /// Get known aliases for the passed group name.
110    pub fn get_aliases_for_group_name(&self, group_name: &String) -> Option<&Vec<Rc<String>>> {
111        self.alias_lookup.get(group_name)
112    }
113
114    /// Get children of the group.
115    pub fn get_children(&self) -> &HashMap<Rc<String>, Rc<Group>> {
116        &self.children
117    }
118
119    /// Get a child known for the passed alias (including name).
120    pub fn get_child_known_for(&self, alias: &str) -> Option<Rc<Group>> {
121        match self.children_lookup.get(&String::from(alias)) {
122            Some(v) => Some(Rc::clone(v)),
123            None => None
124        }
125    }
126
127    /// Get the registered function to consume the parsed arguments and options.
128    pub fn get_consumer(&self) -> &ParserResultConsumer {
129        &self.consumer
130    }
131
132    /// Get the description of the group.
133    pub fn description(&self) -> &String {
134        &self.description
135    }
136}