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}