• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /// Values per occurrence for an argument
2 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
3 pub struct ValueRange {
4     start_inclusive: usize,
5     end_inclusive: usize,
6 }
7 
8 impl ValueRange {
9     /// Nor argument values, or a flag
10     pub const EMPTY: Self = Self {
11         start_inclusive: 0,
12         end_inclusive: 0,
13     };
14 
15     /// A single argument value, the most common case for options
16     pub const SINGLE: Self = Self {
17         start_inclusive: 1,
18         end_inclusive: 1,
19     };
20 
21     /// Create a range
22     ///
23     /// # Panics
24     ///
25     /// If the end is less than the start
26     ///
27     /// # Examples
28     ///
29     /// ```
30     /// # use clap::builder::ValueRange;
31     /// let range = ValueRange::new(5);
32     /// let range = ValueRange::new(5..10);
33     /// let range = ValueRange::new(5..=10);
34     /// let range = ValueRange::new(5..);
35     /// let range = ValueRange::new(..10);
36     /// let range = ValueRange::new(..=10);
37     /// ```
38     ///
39     /// While this will panic:
40     /// ```should_panic
41     /// # use clap::builder::ValueRange;
42     /// let range = ValueRange::new(10..5);  // Panics!
43     /// ```
new(range: impl Into<Self>) -> Self44     pub fn new(range: impl Into<Self>) -> Self {
45         range.into()
46     }
47 
raw(start_inclusive: usize, end_inclusive: usize) -> Self48     pub(crate) fn raw(start_inclusive: usize, end_inclusive: usize) -> Self {
49         debug_assert!(start_inclusive <= end_inclusive);
50         Self {
51             start_inclusive,
52             end_inclusive,
53         }
54     }
55 
56     /// Fewest number of values the argument accepts
min_values(&self) -> usize57     pub fn min_values(&self) -> usize {
58         self.start_inclusive
59     }
60 
61     /// Most number of values the argument accepts
max_values(&self) -> usize62     pub fn max_values(&self) -> usize {
63         self.end_inclusive
64     }
65 
66     /// Report whether the argument takes any values (ie is a flag)
67     ///
68     /// # Examples
69     ///
70     /// ```
71     /// # use clap::builder::ValueRange;
72     /// let range = ValueRange::new(5);
73     /// assert!(range.takes_values());
74     ///
75     /// let range = ValueRange::new(0);
76     /// assert!(!range.takes_values());
77     /// ```
takes_values(&self) -> bool78     pub fn takes_values(&self) -> bool {
79         self.end_inclusive != 0
80     }
81 
is_unbounded(&self) -> bool82     pub(crate) fn is_unbounded(&self) -> bool {
83         self.end_inclusive == usize::MAX
84     }
85 
is_fixed(&self) -> bool86     pub(crate) fn is_fixed(&self) -> bool {
87         self.start_inclusive == self.end_inclusive
88     }
89 
is_multiple(&self) -> bool90     pub(crate) fn is_multiple(&self) -> bool {
91         self.start_inclusive != self.end_inclusive || 1 < self.start_inclusive
92     }
93 
num_values(&self) -> Option<usize>94     pub(crate) fn num_values(&self) -> Option<usize> {
95         self.is_fixed().then_some(self.start_inclusive)
96     }
97 
accepts_more(&self, current: usize) -> bool98     pub(crate) fn accepts_more(&self, current: usize) -> bool {
99         current < self.end_inclusive
100     }
101 }
102 
103 impl std::ops::RangeBounds<usize> for ValueRange {
start_bound(&self) -> std::ops::Bound<&usize>104     fn start_bound(&self) -> std::ops::Bound<&usize> {
105         std::ops::Bound::Included(&self.start_inclusive)
106     }
107 
end_bound(&self) -> std::ops::Bound<&usize>108     fn end_bound(&self) -> std::ops::Bound<&usize> {
109         std::ops::Bound::Included(&self.end_inclusive)
110     }
111 }
112 
113 impl Default for ValueRange {
default() -> Self114     fn default() -> Self {
115         Self::SINGLE
116     }
117 }
118 
119 impl From<usize> for ValueRange {
from(fixed: usize) -> Self120     fn from(fixed: usize) -> Self {
121         (fixed..=fixed).into()
122     }
123 }
124 
125 impl From<std::ops::Range<usize>> for ValueRange {
from(range: std::ops::Range<usize>) -> Self126     fn from(range: std::ops::Range<usize>) -> Self {
127         let start_inclusive = range.start;
128         let end_inclusive = range.end.saturating_sub(1);
129         Self::raw(start_inclusive, end_inclusive)
130     }
131 }
132 
133 impl From<std::ops::RangeFull> for ValueRange {
from(_: std::ops::RangeFull) -> Self134     fn from(_: std::ops::RangeFull) -> Self {
135         let start_inclusive = 0;
136         let end_inclusive = usize::MAX;
137         Self::raw(start_inclusive, end_inclusive)
138     }
139 }
140 
141 impl From<std::ops::RangeFrom<usize>> for ValueRange {
from(range: std::ops::RangeFrom<usize>) -> Self142     fn from(range: std::ops::RangeFrom<usize>) -> Self {
143         let start_inclusive = range.start;
144         let end_inclusive = usize::MAX;
145         Self::raw(start_inclusive, end_inclusive)
146     }
147 }
148 
149 impl From<std::ops::RangeTo<usize>> for ValueRange {
from(range: std::ops::RangeTo<usize>) -> Self150     fn from(range: std::ops::RangeTo<usize>) -> Self {
151         let start_inclusive = 0;
152         let end_inclusive = range.end.saturating_sub(1);
153         Self::raw(start_inclusive, end_inclusive)
154     }
155 }
156 
157 impl From<std::ops::RangeInclusive<usize>> for ValueRange {
from(range: std::ops::RangeInclusive<usize>) -> Self158     fn from(range: std::ops::RangeInclusive<usize>) -> Self {
159         let start_inclusive = *range.start();
160         let end_inclusive = *range.end();
161         Self::raw(start_inclusive, end_inclusive)
162     }
163 }
164 
165 impl From<std::ops::RangeToInclusive<usize>> for ValueRange {
from(range: std::ops::RangeToInclusive<usize>) -> Self166     fn from(range: std::ops::RangeToInclusive<usize>) -> Self {
167         let start_inclusive = 0;
168         let end_inclusive = range.end;
169         Self::raw(start_inclusive, end_inclusive)
170     }
171 }
172 
173 impl std::fmt::Display for ValueRange {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result174     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
175         ok!(self.start_inclusive.fmt(f));
176         if !self.is_fixed() {
177             ok!("..=".fmt(f));
178             ok!(self.end_inclusive.fmt(f));
179         }
180         Ok(())
181     }
182 }
183 
184 impl std::fmt::Debug for ValueRange {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result185     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
186         write!(f, "{self}")
187     }
188 }
189 
190 #[cfg(test)]
191 mod test {
192     use super::*;
193 
194     use std::ops::RangeBounds;
195 
196     #[test]
from_fixed()197     fn from_fixed() {
198         let range: ValueRange = 5.into();
199         assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
200         assert_eq!(range.end_bound(), std::ops::Bound::Included(&5));
201         assert!(range.is_fixed());
202         assert!(range.is_multiple());
203         assert_eq!(range.num_values(), Some(5));
204         assert!(range.takes_values());
205     }
206 
207     #[test]
from_fixed_empty()208     fn from_fixed_empty() {
209         let range: ValueRange = 0.into();
210         assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
211         assert_eq!(range.end_bound(), std::ops::Bound::Included(&0));
212         assert!(range.is_fixed());
213         assert!(!range.is_multiple());
214         assert_eq!(range.num_values(), Some(0));
215         assert!(!range.takes_values());
216     }
217 
218     #[test]
from_range()219     fn from_range() {
220         let range: ValueRange = (5..10).into();
221         assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
222         assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
223         assert!(!range.is_fixed());
224         assert!(range.is_multiple());
225         assert_eq!(range.num_values(), None);
226         assert!(range.takes_values());
227     }
228 
229     #[test]
from_range_inclusive()230     fn from_range_inclusive() {
231         let range: ValueRange = (5..=10).into();
232         assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
233         assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
234         assert!(!range.is_fixed());
235         assert!(range.is_multiple());
236         assert_eq!(range.num_values(), None);
237         assert!(range.takes_values());
238     }
239 
240     #[test]
from_range_full()241     fn from_range_full() {
242         let range: ValueRange = (..).into();
243         assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
244         assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
245         assert!(!range.is_fixed());
246         assert!(range.is_multiple());
247         assert_eq!(range.num_values(), None);
248         assert!(range.takes_values());
249     }
250 
251     #[test]
from_range_from()252     fn from_range_from() {
253         let range: ValueRange = (5..).into();
254         assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
255         assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
256         assert!(!range.is_fixed());
257         assert!(range.is_multiple());
258         assert_eq!(range.num_values(), None);
259         assert!(range.takes_values());
260     }
261 
262     #[test]
from_range_to()263     fn from_range_to() {
264         let range: ValueRange = (..10).into();
265         assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
266         assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
267         assert!(!range.is_fixed());
268         assert!(range.is_multiple());
269         assert_eq!(range.num_values(), None);
270         assert!(range.takes_values());
271     }
272 
273     #[test]
from_range_to_inclusive()274     fn from_range_to_inclusive() {
275         let range: ValueRange = (..=10).into();
276         assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
277         assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
278         assert!(!range.is_fixed());
279         assert!(range.is_multiple());
280         assert_eq!(range.num_values(), None);
281         assert!(range.takes_values());
282     }
283 }
284