1 //! Module with all supported comparison operators. 2 //! 3 //! This module provides an enum with all comparison operators that can be used with this library. 4 //! The enum provides various useful helper functions to inverse or flip an operator. 5 //! 6 //! Methods like `CompOp::from_sign(">");` can be used to get a comparison operator by it's logical 7 //! sign from a string. 8 9 use std::cmp::Ordering; 10 11 /// Enum of supported comparison operators. 12 #[derive(Debug, Clone, PartialEq)] 13 pub enum CompOp { 14 /// Equal (`==`, `=`). 15 /// When version `A` is equal to `B`. 16 Eq, 17 18 /// Not equal (`!=`, `!`, `<>`). 19 /// When version `A` is not equal to `B`. 20 Ne, 21 22 /// Less than (`<`). 23 /// When version `A` is less than `B` but not equal. 24 Lt, 25 26 /// Less or equal (`<=`). 27 /// When version `A` is less than or equal to `B`. 28 Le, 29 30 /// Greater or equal (`>=`). 31 /// When version `A` is greater than or equal to `B`. 32 Ge, 33 34 /// Greater than (`>`). 35 /// When version `A` is greater than `B` but not equal. 36 Gt, 37 } 38 39 impl CompOp { 40 /// Get a comparison operator by it's sign. 41 /// Whitespaces are stripped from the sign string. 42 /// An error is returned if the sign isn't recognized. 43 /// 44 /// The following signs are supported: 45 /// 46 /// * `==` _or_ `=` -> `Eq` 47 /// * `!=` _or_ `!` _or_ `<>` -> `Ne` 48 /// * `< ` -> `Lt` 49 /// * `<=` -> `Le` 50 /// * `>=` -> `Ge` 51 /// * `> ` -> `Gt` 52 /// 53 /// # Examples 54 /// 55 /// ``` 56 /// use version_compare::CompOp; 57 /// 58 /// assert_eq!(CompOp::from_sign("=="), Ok(CompOp::Eq)); 59 /// assert_eq!(CompOp::from_sign("<"), Ok(CompOp::Lt)); 60 /// assert_eq!(CompOp::from_sign(" >= "), Ok(CompOp::Ge)); 61 /// assert!(CompOp::from_sign("*").is_err()); 62 /// ``` from_sign(sign: &str) -> Result<CompOp, ()>63 pub fn from_sign(sign: &str) -> Result<CompOp, ()> { 64 match sign.trim().as_ref() { 65 "==" | "=" => Ok(CompOp::Eq), 66 "!=" | "!" | "<>" => Ok(CompOp::Ne), 67 "<" => Ok(CompOp::Lt), 68 "<=" => Ok(CompOp::Le), 69 ">=" => Ok(CompOp::Ge), 70 ">" => Ok(CompOp::Gt), 71 _ => Err(()), 72 } 73 } 74 75 /// Get a comparison operator by it's name. 76 /// Names are case-insensitive, and whitespaces are stripped from the string. 77 /// An error is returned if the name isn't recognized. 78 /// 79 /// # Examples 80 /// 81 /// ``` 82 /// use version_compare::CompOp; 83 /// 84 /// assert_eq!(CompOp::from_name("eq"), Ok(CompOp::Eq)); 85 /// assert_eq!(CompOp::from_name("lt"), Ok(CompOp::Lt)); 86 /// assert_eq!(CompOp::from_name(" Ge "), Ok(CompOp::Ge)); 87 /// assert!(CompOp::from_name("abc").is_err()); 88 /// ``` from_name(sign: &str) -> Result<CompOp, ()>89 pub fn from_name(sign: &str) -> Result<CompOp, ()> { 90 match sign.trim().to_lowercase().as_ref() { 91 "eq" => Ok(CompOp::Eq), 92 "ne" => Ok(CompOp::Ne), 93 "lt" => Ok(CompOp::Lt), 94 "le" => Ok(CompOp::Le), 95 "ge" => Ok(CompOp::Ge), 96 "gt" => Ok(CompOp::Gt), 97 _ => Err(()), 98 } 99 } 100 101 /// Get the comparison operator from Rusts `Ordering` enum. 102 /// 103 /// The following comparison operators are returned: 104 /// 105 /// * `Ordering::Less` -> `Lt` 106 /// * `Ordering::Equal` -> `Eq` 107 /// * `Ordering::Greater` -> `Gt` from_ord(ord: Ordering) -> CompOp108 pub fn from_ord(ord: Ordering) -> CompOp { 109 match ord { 110 Ordering::Less => CompOp::Lt, 111 Ordering::Equal => CompOp::Eq, 112 Ordering::Greater => CompOp::Gt, 113 } 114 } 115 116 /// Get the name of this comparison operator. 117 /// 118 /// # Examples 119 /// 120 /// ``` 121 /// use version_compare::CompOp; 122 /// 123 /// assert_eq!(CompOp::Eq.name(), "eq"); 124 /// assert_eq!(CompOp::Lt.name(), "lt"); 125 /// assert_eq!(CompOp::Ge.name(), "ge"); 126 /// ``` name(&self) -> &str127 pub fn name(&self) -> &str { 128 match self { 129 &CompOp::Eq => "eq", 130 &CompOp::Ne => "ne", 131 &CompOp::Lt => "lt", 132 &CompOp::Le => "le", 133 &CompOp::Ge => "ge", 134 &CompOp::Gt => "gt", 135 } 136 } 137 138 /// Covert to the inverted comparison operator. 139 /// 140 /// This uses the following bidirectional rules: 141 /// 142 /// * `Eq` <-> `Ne` 143 /// * `Lt` <-> `Ge` 144 /// * `Le` <-> `Gt` 145 /// 146 /// # Examples 147 /// 148 /// ``` 149 /// use version_compare::CompOp; 150 /// 151 /// assert_eq!(CompOp::Eq.as_inverted(), CompOp::Ne); 152 /// assert_eq!(CompOp::Lt.as_inverted(), CompOp::Ge); 153 /// assert_eq!(CompOp::Gt.as_inverted(), CompOp::Le); 154 /// ``` as_inverted(self) -> Self155 pub fn as_inverted(self) -> Self { 156 self.invert() 157 } 158 159 /// Get the inverted comparison operator. 160 /// 161 /// This uses the following bidirectional rules: 162 /// 163 /// * `Eq` <-> `Ne` 164 /// * `Lt` <-> `Ge` 165 /// * `Le` <-> `Gt` 166 /// 167 /// # Examples 168 /// 169 /// ``` 170 /// use version_compare::CompOp; 171 /// 172 /// assert_eq!(CompOp::Eq.invert(), CompOp::Ne); 173 /// assert_eq!(CompOp::Lt.invert(), CompOp::Ge); 174 /// assert_eq!(CompOp::Gt.invert(), CompOp::Le); 175 /// ``` invert(&self) -> Self176 pub fn invert(&self) -> Self { 177 match self { 178 &CompOp::Eq => CompOp::Ne, 179 &CompOp::Ne => CompOp::Eq, 180 &CompOp::Lt => CompOp::Ge, 181 &CompOp::Le => CompOp::Gt, 182 &CompOp::Ge => CompOp::Lt, 183 &CompOp::Gt => CompOp::Le, 184 } 185 } 186 187 /// Convert to the opposite comparison operator. 188 /// 189 /// This uses the following bidirectional rules: 190 /// 191 /// * `Eq` <-> `Ne` 192 /// * `Lt` <-> `Gt` 193 /// * `Le` <-> `Ge` 194 /// 195 /// # Examples 196 /// 197 /// ``` 198 /// use version_compare::CompOp; 199 /// 200 /// assert_eq!(CompOp::Eq.as_opposite(), CompOp::Ne); 201 /// assert_eq!(CompOp::Lt.as_opposite(), CompOp::Gt); 202 /// assert_eq!(CompOp::Ge.as_opposite(), CompOp::Le); 203 /// ``` as_opposite(self) -> Self204 pub fn as_opposite(self) -> Self { 205 self.opposite() 206 } 207 208 /// Get the opposite comparison operator. 209 /// 210 /// This uses the following bidirectional rules: 211 /// 212 /// * `Eq` <-> `Ne` 213 /// * `Lt` <-> `Gt` 214 /// * `Le` <-> `Ge` 215 /// 216 /// # Examples 217 /// 218 /// ``` 219 /// use version_compare::CompOp; 220 /// 221 /// assert_eq!(CompOp::Eq.opposite(), CompOp::Ne); 222 /// assert_eq!(CompOp::Lt.opposite(), CompOp::Gt); 223 /// assert_eq!(CompOp::Ge.opposite(), CompOp::Le); 224 /// ``` opposite(&self) -> Self225 pub fn opposite(&self) -> Self { 226 match self { 227 &CompOp::Eq => CompOp::Ne, 228 &CompOp::Ne => CompOp::Eq, 229 &CompOp::Lt => CompOp::Gt, 230 &CompOp::Le => CompOp::Ge, 231 &CompOp::Ge => CompOp::Le, 232 &CompOp::Gt => CompOp::Lt, 233 } 234 } 235 236 /// Convert to the flipped comparison operator. 237 /// 238 /// This uses the following bidirectional rules: 239 /// 240 /// * `Lt` <-> `Gt` 241 /// * `Le` <-> `Ge` 242 /// * Other operators are returned as is. 243 /// 244 /// # Examples 245 /// 246 /// ``` 247 /// use version_compare::CompOp; 248 /// 249 /// assert_eq!(CompOp::Eq.as_flipped(), CompOp::Eq); 250 /// assert_eq!(CompOp::Lt.as_flipped(), CompOp::Gt); 251 /// assert_eq!(CompOp::Ge.as_flipped(), CompOp::Le); 252 /// ``` as_flipped(self) -> Self253 pub fn as_flipped(self) -> Self { 254 self.flip() 255 } 256 257 /// Get the flipped comparison operator. 258 /// 259 /// This uses the following bidirectional rules: 260 /// 261 /// * `Lt` <-> `Gt` 262 /// * `Le` <-> `Ge` 263 /// * Other operators are returned as is. 264 /// 265 /// # Examples 266 /// 267 /// ``` 268 /// use version_compare::CompOp; 269 /// 270 /// assert_eq!(CompOp::Eq.flip(), CompOp::Eq); 271 /// assert_eq!(CompOp::Lt.flip(), CompOp::Gt); 272 /// assert_eq!(CompOp::Ge.flip(), CompOp::Le); 273 /// ``` flip(&self) -> Self274 pub fn flip(&self) -> Self { 275 match self { 276 &CompOp::Lt => CompOp::Gt, 277 &CompOp::Le => CompOp::Ge, 278 &CompOp::Ge => CompOp::Le, 279 &CompOp::Gt => CompOp::Lt, 280 _ => self.clone(), 281 } 282 } 283 284 /// Get the sign for this comparison operator. 285 /// 286 /// The following signs are returned: 287 /// 288 /// * `Eq` -> `==` 289 /// * `Ne` -> `!=` 290 /// * `Lt` -> `< ` 291 /// * `Le` -> `<=` 292 /// * `Ge` -> `>=` 293 /// * `Gt` -> `> ` 294 /// 295 /// Note: Some comparison operators also support other signs, 296 /// such as `=` for `Eq` and `!` for `Ne`, 297 /// these are never returned by this method however as the table above is used. 298 /// 299 /// # Examples 300 /// 301 /// ``` 302 /// use version_compare::CompOp; 303 /// 304 /// assert_eq!(CompOp::Eq.sign(), "=="); 305 /// assert_eq!(CompOp::Lt.sign(), "<"); 306 /// assert_eq!(CompOp::Ge.flip().sign(), "<="); 307 /// ``` sign(&self) -> &'static str308 pub fn sign(&self) -> &'static str { 309 match self { 310 &CompOp::Eq => "==", 311 &CompOp::Ne => "!=", 312 &CompOp::Lt => "<", 313 &CompOp::Le => "<=", 314 &CompOp::Ge => ">=", 315 &CompOp::Gt => ">", 316 } 317 } 318 319 /// Get a factor (number) for this comparison operator. 320 /// These factors can be useful for quick calculations. 321 /// 322 /// The following factor numbers are returned: 323 /// 324 /// * `Eq` or `Ne` -> ` 0 ` 325 /// * `Lt` or `Le` -> `-1` 326 /// * `Gt` or `Ge` -> ` 1` 327 /// 328 /// # Examples 329 /// 330 /// ``` 331 /// use version_compare::Version; 332 /// 333 /// let ver_a = Version::from("1.2.3").unwrap(); 334 /// let ver_b = Version::from("1.3").unwrap(); 335 /// 336 /// assert_eq!(ver_a.compare(&ver_b).factor(), -1); 337 /// assert_eq!(10 * ver_b.compare(&ver_a).factor(), 10); 338 /// ``` factor(&self) -> i8339 pub fn factor(&self) -> i8 { 340 match self { 341 &CompOp::Eq | &CompOp::Ne => 0, 342 &CompOp::Lt | &CompOp::Le => -1, 343 &CompOp::Gt | &CompOp::Ge => 1, 344 } 345 } 346 347 /// Get Rust's ordering for this comparison operator. 348 /// 349 /// The following comparison operators are supported: 350 /// 351 /// * `Eq` -> `Ordering::Equal` 352 /// * `Lt` -> `Ordering::Less` 353 /// * `Gt` -> `Ordering::Greater` 354 /// 355 /// For other comparison operators `None` is returned. 356 /// 357 /// # Examples 358 /// 359 /// ``` 360 /// use std::cmp::Ordering; 361 /// use version_compare::Version; 362 /// 363 /// let ver_a = Version::from("1.2.3").unwrap(); 364 /// let ver_b = Version::from("1.3").unwrap(); 365 /// 366 /// assert_eq!(ver_a.compare(&ver_b).ord().unwrap(), Ordering::Less); 367 /// ``` ord(&self) -> Option<Ordering>368 pub fn ord(&self) -> Option<Ordering> { 369 match self { 370 &CompOp::Eq => Some(Ordering::Equal), 371 &CompOp::Lt => Some(Ordering::Less), 372 &CompOp::Gt => Some(Ordering::Greater), 373 _ => None, 374 } 375 } 376 } 377 378 #[cfg_attr(tarpaulin, skip)] 379 #[cfg(test)] 380 mod tests { 381 use std::cmp::Ordering; 382 383 use super::CompOp; 384 385 #[test] from_sign()386 fn from_sign() { 387 // Normal signs 388 assert_eq!(CompOp::from_sign("==").unwrap(), CompOp::Eq); 389 assert_eq!(CompOp::from_sign("=").unwrap(), CompOp::Eq); 390 assert_eq!(CompOp::from_sign("!=").unwrap(), CompOp::Ne); 391 assert_eq!(CompOp::from_sign("!").unwrap(), CompOp::Ne); 392 assert_eq!(CompOp::from_sign("<>").unwrap(), CompOp::Ne); 393 assert_eq!(CompOp::from_sign("<").unwrap(), CompOp::Lt); 394 assert_eq!(CompOp::from_sign("<=").unwrap(), CompOp::Le); 395 assert_eq!(CompOp::from_sign(">=").unwrap(), CompOp::Ge); 396 assert_eq!(CompOp::from_sign(">").unwrap(), CompOp::Gt); 397 398 // Exceptional cases 399 assert_eq!(CompOp::from_sign(" <= ").unwrap(), CompOp::Le); 400 assert!(CompOp::from_sign("*").is_err()); 401 } 402 403 #[test] from_name()404 fn from_name() { 405 // Normal names 406 assert_eq!(CompOp::from_name("eq").unwrap(), CompOp::Eq); 407 assert_eq!(CompOp::from_name("ne").unwrap(), CompOp::Ne); 408 assert_eq!(CompOp::from_name("lt").unwrap(), CompOp::Lt); 409 assert_eq!(CompOp::from_name("le").unwrap(), CompOp::Le); 410 assert_eq!(CompOp::from_name("ge").unwrap(), CompOp::Ge); 411 assert_eq!(CompOp::from_name("gt").unwrap(), CompOp::Gt); 412 413 // Exceptional cases 414 assert_eq!(CompOp::from_name(" Le ").unwrap(), CompOp::Le); 415 assert!(CompOp::from_name("abc").is_err()); 416 } 417 418 #[test] from_ord()419 fn from_ord() { 420 assert_eq!(CompOp::from_ord(Ordering::Less), CompOp::Lt); 421 assert_eq!(CompOp::from_ord(Ordering::Equal), CompOp::Eq); 422 assert_eq!(CompOp::from_ord(Ordering::Greater), CompOp::Gt); 423 } 424 425 #[test] name()426 fn name() { 427 assert_eq!(CompOp::Eq.name(), "eq"); 428 assert_eq!(CompOp::Ne.name(), "ne"); 429 assert_eq!(CompOp::Lt.name(), "lt"); 430 assert_eq!(CompOp::Le.name(), "le"); 431 assert_eq!(CompOp::Ge.name(), "ge"); 432 assert_eq!(CompOp::Gt.name(), "gt"); 433 } 434 435 #[test] as_inverted()436 fn as_inverted() { 437 assert_eq!(CompOp::Ne.as_inverted(), CompOp::Eq); 438 assert_eq!(CompOp::Eq.as_inverted(), CompOp::Ne); 439 assert_eq!(CompOp::Ge.as_inverted(), CompOp::Lt); 440 assert_eq!(CompOp::Gt.as_inverted(), CompOp::Le); 441 assert_eq!(CompOp::Lt.as_inverted(), CompOp::Ge); 442 assert_eq!(CompOp::Le.as_inverted(), CompOp::Gt); 443 } 444 445 #[test] invert()446 fn invert() { 447 assert_eq!(CompOp::Ne.invert(), CompOp::Eq); 448 assert_eq!(CompOp::Eq.invert(), CompOp::Ne); 449 assert_eq!(CompOp::Ge.invert(), CompOp::Lt); 450 assert_eq!(CompOp::Gt.invert(), CompOp::Le); 451 assert_eq!(CompOp::Lt.invert(), CompOp::Ge); 452 assert_eq!(CompOp::Le.invert(), CompOp::Gt); 453 } 454 455 #[test] as_opposite()456 fn as_opposite() { 457 assert_eq!(CompOp::Ne.as_opposite(), CompOp::Eq); 458 assert_eq!(CompOp::Eq.as_opposite(), CompOp::Ne); 459 assert_eq!(CompOp::Gt.as_opposite(), CompOp::Lt); 460 assert_eq!(CompOp::Ge.as_opposite(), CompOp::Le); 461 assert_eq!(CompOp::Le.as_opposite(), CompOp::Ge); 462 assert_eq!(CompOp::Lt.as_opposite(), CompOp::Gt); 463 } 464 465 #[test] opposite()466 fn opposite() { 467 assert_eq!(CompOp::Eq.opposite(), CompOp::Ne); 468 assert_eq!(CompOp::Ne.opposite(), CompOp::Eq); 469 assert_eq!(CompOp::Lt.opposite(), CompOp::Gt); 470 assert_eq!(CompOp::Le.opposite(), CompOp::Ge); 471 assert_eq!(CompOp::Ge.opposite(), CompOp::Le); 472 assert_eq!(CompOp::Gt.opposite(), CompOp::Lt); 473 } 474 475 #[test] as_flipped()476 fn as_flipped() { 477 assert_eq!(CompOp::Eq.as_flipped(), CompOp::Eq); 478 assert_eq!(CompOp::Ne.as_flipped(), CompOp::Ne); 479 assert_eq!(CompOp::Lt.as_flipped(), CompOp::Gt); 480 assert_eq!(CompOp::Le.as_flipped(), CompOp::Ge); 481 assert_eq!(CompOp::Ge.as_flipped(), CompOp::Le); 482 assert_eq!(CompOp::Gt.as_flipped(), CompOp::Lt); 483 } 484 485 #[test] flip()486 fn flip() { 487 assert_eq!(CompOp::Eq.flip(), CompOp::Eq); 488 assert_eq!(CompOp::Ne.flip(), CompOp::Ne); 489 assert_eq!(CompOp::Lt.flip(), CompOp::Gt); 490 assert_eq!(CompOp::Le.flip(), CompOp::Ge); 491 assert_eq!(CompOp::Ge.flip(), CompOp::Le); 492 assert_eq!(CompOp::Gt.flip(), CompOp::Lt); 493 } 494 495 #[test] sign()496 fn sign() { 497 assert_eq!(CompOp::Eq.sign(), "=="); 498 assert_eq!(CompOp::Ne.sign(), "!="); 499 assert_eq!(CompOp::Lt.sign(), "<"); 500 assert_eq!(CompOp::Le.sign(), "<="); 501 assert_eq!(CompOp::Ge.sign(), ">="); 502 assert_eq!(CompOp::Gt.sign(), ">"); 503 } 504 505 #[test] factor()506 fn factor() { 507 assert_eq!(CompOp::Eq.factor(), 0); 508 assert_eq!(CompOp::Ne.factor(), 0); 509 assert_eq!(CompOp::Lt.factor(), -1); 510 assert_eq!(CompOp::Le.factor(), -1); 511 assert_eq!(CompOp::Ge.factor(), 1); 512 assert_eq!(CompOp::Gt.factor(), 1); 513 } 514 515 #[test] ord()516 fn ord() { 517 assert_eq!(CompOp::Eq.ord(), Some(Ordering::Equal)); 518 assert_eq!(CompOp::Ne.ord(), None); 519 assert_eq!(CompOp::Lt.ord(), Some(Ordering::Less)); 520 assert_eq!(CompOp::Le.ord(), None); 521 assert_eq!(CompOp::Ge.ord(), None); 522 assert_eq!(CompOp::Gt.ord(), Some(Ordering::Greater)); 523 } 524 } 525