1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use crate::traits::Flag;
use crate::element::Element;
use std::cell::RefCell;
/// The structure that holds all the user defined flags.
pub struct Flags<'a> {
counter: RefCell<usize>,
flags: RefCell<Vec<Element<'a>>>,
}
impl<'a> Flags<'a> {
/// Initialize the Flags struct.
pub fn new() -> Self {
Self {
counter: RefCell::new(0),
flags: RefCell::new(Vec::new()),
}
}
/// Adds a user defined flag in the flags struct and returns a mutable reference to the value
/// that the user provided.
/// # Examples
/// ```
/// // initialize the flags struct.
/// use flagtory::Flags;
/// let flags = Flags::new();
///
/// // adds a flag named t to the flags struct.
/// let value_ref = flags.add("t","this is the t flag", 25);
///
/// assert_eq!(*value_ref, 25);
/// ```
/// the value can be mutated by the user
/// ```
/// use flagtory::Flags;
/// // initialize the flags struct.
/// let flags = Flags::new();
///
/// // add a flag named w to the flags struct.
/// let value_ref = flags.add("w","this is the w flag", 65);
///
/// // modify the value
/// *value_ref = 55;
///
/// assert_eq!(*value_ref, 55);
///
/// ```
///
pub fn add<T: Flag + 'static>(&self, name: &'a str, description: &'a str, value: T) -> &mut T {
*self.counter.borrow_mut() += 1;
let flag = Element::new(
name,
description,
value
);
self.flags.borrow_mut().push(flag);
return unsafe { &mut *self.flags.borrow_mut()[*self.counter.borrow()-1].get::<T>() };
}
/// parses the user argument provided in [`std::env::args`].
/// Note that this method will find the flags that the user defined and change the value of the
/// flag based on the argument provided.
pub fn parse(&self) {
// the reason why i need to slicee it because the first argument is the path to the
// executable meanwhile the rest is what the user is going to type.
let provided_arguments = &std::env::args().collect::<Vec<String>>()[1..];
// iterate through all the provided_arguments
for (index,argument) in provided_arguments.iter().enumerate() {
let arg = &**argument;
// check if this is not a flag
if arg.starts_with("--") == false && arg.starts_with("-") == false {
continue;
}
if let Some(valid_name) = arg.strip_prefix("--") {
// this is basically checking if the flag in the end of the user provided argument
// has no value like the -b flag for example`-w 88 -h 88 -b`
// this b flag is assumed to be a boolean flag same as name if the order is like
// this
// -w 88 -b -h 88
if index + 1 == provided_arguments.len() {
if let Some(flag) = self.flags.borrow_mut().iter_mut().find(|x| x.name == valid_name.split("-").collect::<Vec<&str>>().join("")) {
*flag.value.as_any().downcast_mut::<bool>().unwrap() = !(*flag.value.as_any().downcast_mut::<bool>().unwrap());
}
} else {
// this is basically turn the user defined flag comparable to the real flag
// e.g: defined as `allow net`
// e.g: user argument as `--allow-net`
// if it succeeded to strip it prefix it will turn into allow-net then we must
// split it by the dash to [allow,net] and then join it by using a space to
// allow net.
if let Some(flag) = self.flags.borrow_mut().iter_mut().find(|x| x.name == valid_name.split("-").collect::<Vec<&str>>().join("")) {
// check if the flags value is another flag (this means the flag is assumed to be a boolean flag)
let user_provided_value = &*provided_arguments[index+1];
if user_provided_value.starts_with("--") == false && user_provided_value.starts_with("-") == false {
flag.value.into_flag(user_provided_value);
} else {
*flag.value.as_any().downcast_mut::<bool>().unwrap() = !(*flag.value.as_any().downcast_mut::<bool>().unwrap());
}
}
}
}
if let Some(valid_name) = arg.strip_prefix("-") {
if index+1 == provided_arguments.len() {
if let Some(flag) = self.flags.borrow_mut().iter_mut().find(|x| x.name == valid_name) {
*flag.value.as_any().downcast_mut::<bool>().unwrap() = !(*flag.value.as_any().downcast_mut::<bool>().unwrap());
}
} else {
if let Some(flag) = self.flags.borrow_mut().iter_mut().find(|x| x.name == valid_name) {
let user_provided_value = &*provided_arguments[index+1];
if user_provided_value.starts_with("--") == false && user_provided_value.starts_with("-") == false {
flag.value.into_flag(user_provided_value);
} else {
*flag.value.as_any().downcast_mut::<bool>().unwrap() = !(*flag.value.as_any().downcast_mut::<bool>().unwrap());
}
}
}
}
}
}
}