1use std::collections::{HashSet, HashMap};
2
3#[derive(Clone, Debug, Eq, PartialEq)]
4pub struct CLIParser {
5
6 pub posits: Vec<String>,
15
16 pub flags: HashSet<String>,
25
26 pub pairs: HashMap<String, String>,
35}
36
37
38#[derive(Clone, Debug, Eq, PartialEq)]
39pub enum CLIError {
40 FlagWithSign(String),
41 FlagMalformed(String),
42 PairMissingSign(String),
43 PairBadSign(String),
44 PairMalformed(String),
45 DashesMalformed(String)
46}
47
48
49impl std::error::Error for CLIError {
51 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
52 match *self {
53 CLIError::FlagWithSign(_) => None,
54 CLIError::FlagMalformed(_) => None,
55 CLIError::PairMissingSign(_) => None,
56 CLIError::PairBadSign(_) => None,
57 CLIError::PairMalformed(_) => None,
58 CLIError::DashesMalformed(_) => None,
59 }
60 }
61}
62
63
64impl std::fmt::Display for CLIError {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 match *self {
67 CLIError::FlagWithSign(ref arg) => write!(f, "Equal signs not allowed in flags: `{0}`\nProper syntax: `./my_program -flag`", arg),
68 CLIError::FlagMalformed(ref arg) => write!(f, "Malformed flag: `{0}`\nProper syntax: `./my_program -flag`", arg),
69 CLIError::PairMissingSign(ref arg) => write!(f, "Key-value pair arguments need an equal sign: `{0}`\nProper syntax: `./my_program --key=value`", arg),
70 CLIError::PairBadSign(ref arg) => write!(f, "Improper use of equal sign in key-value pair: `{0}`\nProper syntax: `./my_program --key=value`", arg),
71 CLIError::PairMalformed(ref arg) => write!(f, "Malformed key-value pair: `{0}`\nProper syntax: `./my_program --key=value`", arg),
72 CLIError::DashesMalformed(ref arg) => write!(f, "Arguments cannot start with 3 or more dash lines: `{0}`", arg),
73 }
74 }
75}
76
77impl Default for CLIParser {
78 fn default() -> Self {
79 Self {
80 posits: Vec::new(),
81 flags: HashSet::new(),
82 pairs: HashMap::new(),
83 }
84 }
85}
86
87impl CLIParser {
88
89 pub fn new() -> Self {
91 Self::default()
92 }
93
94 pub fn init(mut self) -> Result<Self, CLIError> {
108
109 for argument in std::env::args() {
110
111 if !argument.starts_with("-") {
113 self.posits.push(argument);
114 continue;
115 }
116
117 else if !argument.starts_with("--") {
118
119 if argument.contains("=") {
120 return Err(CLIError::FlagWithSign(argument));
121 }
122
123 if argument.len() < 2 {
124 return Err(CLIError::FlagWithSign(argument));
125 }
126
127 self.flags.insert(argument[1..].to_string());
128 continue;
129 }
130
131 else if !argument.starts_with("---") {
132 if !argument.contains("=") {
133 return Err(CLIError::PairMissingSign(argument));
134 }
135
136 if argument.len() < 5 {
137 return Err(CLIError::PairMalformed(argument));
138 }
139
140 let equal_sign_pos: usize = argument.find('=').unwrap();
141 if equal_sign_pos == 2 || equal_sign_pos == argument.len() - 1 {
142 return Err(CLIError::PairBadSign(argument));
143 }
144
145 let kwarg: (&str, &str) = argument.split_once("=").unwrap();
146 self.pairs.insert(kwarg.0[2..].to_string(), kwarg.1.to_string());
147 }
148
149 else {
150 return Err(CLIError::DashesMalformed(argument));
151 }
152 }
153
154 Ok(self)
155 }
156
157}
158