1 //! Utilities for dealing with argument flags
6 /// Determines whether a `--flag` is present.
7 pub fn has_arg_flag(name: &str) -> bool {
11 /// Determines how many times a `--flag` is present.
12 pub fn num_arg_flag(name: &str) -> usize {
13 env::args().take_while(|val| val != "--").filter(|val| val == name).count()
16 /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except
17 /// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.)
18 pub struct ArgSplitFlagValue<'a, I> {
23 impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> {
24 fn new(args: I, name: &'a str) -> Self {
25 Self { args: Some(args), name }
29 impl<'s, I: Iterator<Item = Cow<'s, str>>> Iterator for ArgSplitFlagValue<'_, I> {
30 // If the original iterator was all `Owned`, then we will only ever yield `Owned`
31 // (so `into_owned()` is cheap).
32 type Item = Result<Cow<'s, str>, Cow<'s, str>>;
34 fn next(&mut self) -> Option<Self::Item> {
35 let Some(args) = self.args.as_mut() else {
36 // We already canceled this iterator.
39 let arg = args.next()?;
41 // Stop searching at `--`.
45 // These branches cannot be merged if we want to avoid the allocation in the `Borrowed` branch.
48 if let Some(suffix) = arg.strip_prefix(self.name) {
49 // Strip leading `name`.
50 if suffix.is_empty() {
51 // This argument is exactly `name`; the next one is the value.
52 return args.next().map(Ok);
53 } else if let Some(suffix) = suffix.strip_prefix('=') {
54 // This argument is `name=value`; get the value.
55 return Some(Ok(Cow::Borrowed(suffix)));
59 if let Some(suffix) = arg.strip_prefix(self.name) {
60 // Strip leading `name`.
61 if suffix.is_empty() {
62 // This argument is exactly `name`; the next one is the value.
63 return args.next().map(Ok);
64 } else if let Some(suffix) = suffix.strip_prefix('=') {
65 // This argument is `name=value`; get the value. We need to do an allocation
66 // here as a `String` cannot be subsliced (what would the lifetime be?).
67 return Some(Ok(Cow::Owned(suffix.to_owned())));
75 impl<'a, I: Iterator<Item = String> + 'a> ArgSplitFlagValue<'a, I> {
76 pub fn from_string_iter(
79 ) -> impl Iterator<Item = Result<String, String>> + 'a {
80 ArgSplitFlagValue::new(args.map(Cow::Owned), name).map(|x| {
82 Ok(Cow::Owned(s)) => Ok(s),
83 Err(Cow::Owned(s)) => Err(s),
84 _ => panic!("iterator converted owned to borrowed"),
90 impl<'x: 'a, 'a, I: Iterator<Item = &'x str> + 'a> ArgSplitFlagValue<'a, I> {
94 ) -> impl Iterator<Item = Result<&'x str, &'x str>> + 'a {
95 ArgSplitFlagValue::new(args.map(Cow::Borrowed), name).map(|x| {
97 Ok(Cow::Borrowed(s)) => Ok(s),
98 Err(Cow::Borrowed(s)) => Err(s),
99 _ => panic!("iterator converted borrowed to owned"),
105 /// Yields all values of command line flag `name`.
106 pub struct ArgFlagValueIter;
108 impl ArgFlagValueIter {
109 pub fn from_string_iter<'a, I: Iterator<Item = String> + 'a>(
112 ) -> impl Iterator<Item = String> + 'a {
113 ArgSplitFlagValue::from_string_iter(args, name).filter_map(Result::ok)
117 impl ArgFlagValueIter {
118 pub fn from_str_iter<'x: 'a, 'a, I: Iterator<Item = &'x str> + 'a>(
121 ) -> impl Iterator<Item = &'x str> + 'a {
122 ArgSplitFlagValue::from_str_iter(args, name).filter_map(Result::ok)
126 /// Gets the values of a `--flag`.
127 pub fn get_arg_flag_values(name: &str) -> impl Iterator<Item = String> + '_ {
128 ArgFlagValueIter::from_string_iter(env::args(), name)
131 /// Gets the value of a `--flag`.
132 pub fn get_arg_flag_value(name: &str) -> Option<String> {
133 get_arg_flag_values(name).next()