parse_argument/lib.rs
1//! There are two ways to interact with `Pars_argument`:
2//!
3//! * **`parse_argument`**: Parse_argument will try to find a specified flag (key) and try to parse the value.
4//! can be used with any type that implements `FromStr`.
5//!
6//! * **`args_to_hashmap`**: Puts all args with a key/value pair into a hashmap. Key and values are both String type so you;ll have to convert it yourself.
7//!
8//! _[crates.io link](https://crates.io/crates/parse_argument) | [Github repo](https://github.com/connorm400/parse_arguments_rs/)_
9
10use std::env::args;
11use std::str::FromStr;
12
13/// Errors for parse_argument(). Takes type `<<T as FromStr>::Err>`
14#[derive(Debug, PartialEq)]
15pub enum ParseArgumentError<T> {
16 BadLen,
17 ParseError(T)
18}
19type Err<T> = ParseArgumentError<<T as FromStr>::Err>;
20
21/// Takes an argument flag, and a type (generally with turbofish syntax).
22/// Will look for any arguments in `std::env::args` that contains `--{flag}=`.
23/// Then it will split it and try to parse it.
24///
25/// Can be used with any type that implements `std::str::FromStr`. You can
26/// implement it for your own custom types.
27///
28/// Usefull for adding extra runtime settings to a cli application.
29///
30/// **_Make sure your argument / value does not have spaces. At least currently, it will not work._**
31///
32/// # Errors
33/// * None if the argument isn't used by the end user
34///
35/// * `Some(Err(ParseArgumentError::BadLen))` if there the vector from splitting the argument by
36/// the `=` sign's length isn't 2 (as in key and value). That also means you can't have equal signs in
37/// your arguments.
38///
39/// * `Some(Err(ParseArgumentError::ParseError(ParseError)))` if parsing the value doesn't work out
40///
41/// # Example
42///
43/// ```
44/// // assuming you run this as "cargo r -- --num=2"
45/// println!("{:?}",
46/// parse_argument::<u8>("num")
47/// );
48/// ```
49pub fn parse_argument<T>(flag: &str) -> Option<Result<T, Err<T>>>
50where T: FromStr {
51 args().find(|x| x.contains(format!("--{flag}=").as_str()))
52 .and_then(|x| {
53 let split_vec: Vec<&str> = x.split("=").collect();
54 match split_vec.len() {
55 2 => Some(split_vec[1].parse::<T>().map_err(|e| ParseArgumentError::ParseError(e))),
56 _ => Some(Err(ParseArgumentError::BadLen))
57 }
58 })
59}
60
61use std::collections::HashMap;
62/// Returns commandline arguments in a hashmap (T and E are Strings).
63///
64/// To be a part of the hashmap, the argument must have this formatting:
65///
66/// ```bash
67/// ./rust_code --argument=true --hello=foo --num=42
68/// ```
69/// And you could access these by doing this in rust:
70/// ```
71/// let arguments = args_to_hashmap();
72/// println!("{arguments:?}");
73/// //will return {"argument": "true", "hello": "foo", "num": "42"}
74/// ```
75pub fn args_to_hashmap() -> HashMap<String, String> {
76 let mut map = HashMap::new();
77 for arg in args() {
78 arg.strip_prefix("--").and_then(|a| {
79 let split_a: Vec<&str> = a.split("=").collect();
80 match split_a.len() {
81 2 => Some(map.entry(split_a[0].to_owned()).or_insert(split_a[1].to_owned())),
82 _ => None
83 }
84 });
85 }
86 map
87}
88
89// its not very possible to test parse_argument<T> since its basically just a procedure
90// that analyzes a side effect of sorts.
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn example_test() {
97 assert_eq!(parse_argument::<String>("hello"), None);
98 }
99}