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