rustlings

solving rustlings ft. dracuxan
git clone [email protected]:dracuxan/rustlings.git
Log | Files | Refs

errors6.rs (2939B)


      1 // Using catch-all error types like `Box<dyn Error>` isn't recommended for
      2 // library code where callers might want to make decisions based on the error
      3 // content instead of printing it out or propagating it further. Here, we define
      4 // a custom error type to make it possible for callers to decide what to do next
      5 // when our function returns an error.
      6 
      7 use std::num::ParseIntError;
      8 
      9 #[derive(PartialEq, Debug)]
     10 enum CreationError {
     11     Negative,
     12     Zero,
     13 }
     14 
     15 // A custom error type that we will be using in `PositiveNonzeroInteger::parse`.
     16 #[derive(PartialEq, Debug)]
     17 enum ParsePosNonzeroError {
     18     Creation(CreationError),
     19     ParseInt(ParseIntError),
     20 }
     21 
     22 impl ParsePosNonzeroError {
     23     fn from_creation(err: CreationError) -> Self {
     24         Self::Creation(err)
     25     }
     26 
     27     fn from_parse_int(err: ParseIntError) -> Self {
     28         Self::ParseInt(err)
     29     }
     30 }
     31 
     32 // As an alternative solution, implementing the `From` trait allows for the
     33 // automatic conversion from a `ParseIntError` into a `ParsePosNonzeroError`
     34 // using the `?` operator, without the need to call `map_err`.
     35 //
     36 // ```
     37 // let x: i64 = s.parse()?;
     38 // ```
     39 //
     40 // Traits like `From` will be dealt with in later exercises.
     41 impl From<ParseIntError> for ParsePosNonzeroError {
     42     fn from(err: ParseIntError) -> Self {
     43         ParsePosNonzeroError::ParseInt(err)
     44     }
     45 }
     46 
     47 #[derive(PartialEq, Debug)]
     48 struct PositiveNonzeroInteger(u64);
     49 
     50 impl PositiveNonzeroInteger {
     51     fn new(value: i64) -> Result<Self, CreationError> {
     52         match value {
     53             x if x < 0 => Err(CreationError::Negative),
     54             0 => Err(CreationError::Zero),
     55             x => Ok(Self(x as u64)),
     56         }
     57     }
     58 
     59     fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> {
     60         // Return an appropriate error instead of panicking when `parse()`
     61         // returns an error.
     62         let x: i64 = s.parse().map_err(ParsePosNonzeroError::from_parse_int)?;
     63         //                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     64         Self::new(x).map_err(ParsePosNonzeroError::from_creation)
     65     }
     66 }
     67 
     68 fn main() {
     69     // You can optionally experiment here.
     70 }
     71 
     72 #[cfg(test)]
     73 mod test {
     74     use super::*;
     75 
     76     #[test]
     77     fn test_parse_error() {
     78         assert!(matches!(
     79             PositiveNonzeroInteger::parse("not a number"),
     80             Err(ParsePosNonzeroError::ParseInt(_)),
     81         ));
     82     }
     83 
     84     #[test]
     85     fn test_negative() {
     86         assert_eq!(
     87             PositiveNonzeroInteger::parse("-555"),
     88             Err(ParsePosNonzeroError::Creation(CreationError::Negative)),
     89         );
     90     }
     91 
     92     #[test]
     93     fn test_zero() {
     94         assert_eq!(
     95             PositiveNonzeroInteger::parse("0"),
     96             Err(ParsePosNonzeroError::Creation(CreationError::Zero)),
     97         );
     98     }
     99 
    100     #[test]
    101     fn test_positive() {
    102         let x = PositiveNonzeroInteger::new(42).unwrap();
    103         assert_eq!(x.0, 42);
    104         assert_eq!(PositiveNonzeroInteger::parse("42"), Ok(x));
    105     }
    106 }