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