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 (debug builds)
26     ///
27     /// # Examples
28     ///
29     /// ```rust
30     /// # use clap_builder as clap;
31     /// # use clap::builder::ValueRange;
32     /// let range = ValueRange::new(5);
33     /// let range = ValueRange::new(5..10);
34     /// let range = ValueRange::new(5..=10);
35     /// let range = ValueRange::new(5..);
36     /// let range = ValueRange::new(..10);
37     /// let range = ValueRange::new(..=10);
38     /// ```
39     ///
40     /// While this will panic:
41     /// ```should_panic
42     /// # use clap_builder as clap;
43     /// # use clap::builder::ValueRange;
44     /// let range = ValueRange::new(10..5);  // Panics!
45     /// ```
new(range: impl Into<Self>) -> Self46     pub fn new(range: impl Into<Self>) -> Self {
47         range.into()
48     }
49 
raw(start_inclusive: usize, end_inclusive: usize) -> Self50     pub(crate) fn raw(start_inclusive: usize, end_inclusive: usize) -> Self {
51         debug_assert!(start_inclusive <= end_inclusive);
52         Self {
53             start_inclusive,
54             end_inclusive,
55         }
56     }
57 
58     /// Fewest number of values the argument accepts
min_values(&self) -> usize59     pub fn min_values(&self) -> usize {
60         self.start_inclusive
61     }
62 
63     /// Most number of values the argument accepts
max_values(&self) -> usize64     pub fn max_values(&self) -> usize {
65         self.end_inclusive
66     }
67 
68     /// Report whether the argument takes any values (ie is a flag)
69     ///
70     /// # Examples
71     ///
72     /// ```rust
73     /// # use clap_builder as clap;
74     /// # use clap::builder::ValueRange;
75     /// let range = ValueRange::new(5);
76     /// assert!(range.takes_values());
77     ///
78     /// let range = ValueRange::new(0);
79     /// assert!(!range.takes_values());
80     /// ```
takes_values(&self) -> bool81     pub fn takes_values(&self) -> bool {
82         self.end_inclusive != 0
83     }
84 
is_unbounded(&self) -> bool85     pub(crate) fn is_unbounded(&self) -> bool {
86         self.end_inclusive == usize::MAX
87     }
88 
is_fixed(&self) -> bool89     pub(crate) fn is_fixed(&self) -> bool {
90         self.start_inclusive == self.end_inclusive
91     }
92 
is_multiple(&self) -> bool93     pub(crate) fn is_multiple(&self) -> bool {
94         self.start_inclusive != self.end_inclusive || 1 < self.start_inclusive
95     }
96 
num_values(&self) -> Option<usize>97     pub(crate) fn num_values(&self) -> Option<usize> {
98         self.is_fixed().then_some(self.start_inclusive)
99     }
100 
accepts_more(&self, current: usize) -> bool101     pub(crate) fn accepts_more(&self, current: usize) -> bool {
102         current < self.end_inclusive
103     }
104 }
105 
106 impl std::ops::RangeBounds<usize> for ValueRange {
start_bound(&self) -> std::ops::Bound<&usize>107     fn start_bound(&self) -> std::ops::Bound<&usize> {
108         std::ops::Bound::Included(&self.start_inclusive)
109     }
110 
end_bound(&self) -> std::ops::Bound<&usize>111     fn end_bound(&self) -> std::ops::Bound<&usize> {
112         std::ops::Bound::Included(&self.end_inclusive)
113     }
114 }
115 
116 impl Default for ValueRange {
default() -> Self117     fn default() -> Self {
118         Self::SINGLE
119     }
120 }
121 
122 impl From<usize> for ValueRange {
from(fixed: usize) -> Self123     fn from(fixed: usize) -> Self {
124         (fixed..=fixed).into()
125     }
126 }
127 
128 impl From<std::ops::Range<usize>> for ValueRange {
from(range: std::ops::Range<usize>) -> Self129     fn from(range: std::ops::Range<usize>) -> Self {
130         let start_inclusive = range.start;
131         let end_inclusive = range.end.saturating_sub(1);
132         Self::raw(start_inclusive, end_inclusive)
133     }
134 }
135 
136 impl From<std::ops::RangeFull> for ValueRange {
from(_: std::ops::RangeFull) -> Self137     fn from(_: std::ops::RangeFull) -> Self {
138         let start_inclusive = 0;
139         let end_inclusive = usize::MAX;
140         Self::raw(start_inclusive, end_inclusive)
141     }
142 }
143 
144 impl From<std::ops::RangeFrom<usize>> for ValueRange {
from(range: std::ops::RangeFrom<usize>) -> Self145     fn from(range: std::ops::RangeFrom<usize>) -> Self {
146         let start_inclusive = range.start;
147         let end_inclusive = usize::MAX;
148         Self::raw(start_inclusive, end_inclusive)
149     }
150 }
151 
152 impl From<std::ops::RangeTo<usize>> for ValueRange {
from(range: std::ops::RangeTo<usize>) -> Self153     fn from(range: std::ops::RangeTo<usize>) -> Self {
154         let start_inclusive = 0;
155         let end_inclusive = range.end.saturating_sub(1);
156         Self::raw(start_inclusive, end_inclusive)
157     }
158 }
159 
160 impl From<std::ops::RangeInclusive<usize>> for ValueRange {
from(range: std::ops::RangeInclusive<usize>) -> Self161     fn from(range: std::ops::RangeInclusive<usize>) -> Self {
162         let start_inclusive = *range.start();
163         let end_inclusive = *range.end();
164         Self::raw(start_inclusive, end_inclusive)
165     }
166 }
167 
168 impl From<std::ops::RangeToInclusive<usize>> for ValueRange {
from(range: std::ops::RangeToInclusive<usize>) -> Self169     fn from(range: std::ops::RangeToInclusive<usize>) -> Self {
170         let start_inclusive = 0;
171         let end_inclusive = range.end;
172         Self::raw(start_inclusive, end_inclusive)
173     }
174 }
175 
176 impl std::fmt::Display for ValueRange {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result177     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
178         ok!(self.start_inclusive.fmt(f));
179         if !self.is_fixed() {
180             ok!("..=".fmt(f));
181             ok!(self.end_inclusive.fmt(f));
182         }
183         Ok(())
184     }
185 }
186 
187 impl std::fmt::Debug for ValueRange {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result188     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
189         write!(f, "{self}")
190     }
191 }
192 
193 #[cfg(test)]
194 mod test {
195     use super::*;
196 
197     use std::ops::RangeBounds;
198 
199     #[test]
from_fixed()200     fn from_fixed() {
201         let range: ValueRange = 5.into();
202         assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
203         assert_eq!(range.end_bound(), std::ops::Bound::Included(&5));
204         assert!(range.is_fixed());
205         assert!(range.is_multiple());
206         assert_eq!(range.num_values(), Some(5));
207         assert!(range.takes_values());
208     }
209 
210     #[test]
from_fixed_empty()211     fn from_fixed_empty() {
212         let range: ValueRange = 0.into();
213         assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
214         assert_eq!(range.end_bound(), std::ops::Bound::Included(&0));
215         assert!(range.is_fixed());
216         assert!(!range.is_multiple());
217         assert_eq!(range.num_values(), Some(0));
218         assert!(!range.takes_values());
219     }
220 
221     #[test]
from_range()222     fn from_range() {
223         let range: ValueRange = (5..10).into();
224         assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
225         assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
226         assert!(!range.is_fixed());
227         assert!(range.is_multiple());
228         assert_eq!(range.num_values(), None);
229         assert!(range.takes_values());
230     }
231 
232     #[test]
from_range_inclusive()233     fn from_range_inclusive() {
234         let range: ValueRange = (5..=10).into();
235         assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
236         assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
237         assert!(!range.is_fixed());
238         assert!(range.is_multiple());
239         assert_eq!(range.num_values(), None);
240         assert!(range.takes_values());
241     }
242 
243     #[test]
from_range_full()244     fn from_range_full() {
245         let range: ValueRange = (..).into();
246         assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
247         assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
248         assert!(!range.is_fixed());
249         assert!(range.is_multiple());
250         assert_eq!(range.num_values(), None);
251         assert!(range.takes_values());
252     }
253 
254     #[test]
from_range_from()255     fn from_range_from() {
256         let range: ValueRange = (5..).into();
257         assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
258         assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
259         assert!(!range.is_fixed());
260         assert!(range.is_multiple());
261         assert_eq!(range.num_values(), None);
262         assert!(range.takes_values());
263     }
264 
265     #[test]
from_range_to()266     fn from_range_to() {
267         let range: ValueRange = (..10).into();
268         assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
269         assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
270         assert!(!range.is_fixed());
271         assert!(range.is_multiple());
272         assert_eq!(range.num_values(), None);
273         assert!(range.takes_values());
274     }
275 
276     #[test]
from_range_to_inclusive()277     fn from_range_to_inclusive() {
278         let range: ValueRange = (..=10).into();
279         assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
280         assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
281         assert!(!range.is_fixed());
282         assert!(range.is_multiple());
283         assert_eq!(range.num_values(), None);
284         assert!(range.takes_values());
285     }
286 }
287