From 55ad8565ff1f247732f9bc0814d746e6eb2d8216 Mon Sep 17 00:00:00 2001 From: Charles Tison Date: Tue, 31 Mar 2020 10:09:12 +0200 Subject: [PATCH] Refactor errors --- src/errs.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 35 +++++++++++++++-------------- src/main.rs | 2 +- 3 files changed, 84 insertions(+), 17 deletions(-) create mode 100644 src/errs.rs diff --git a/src/errs.rs b/src/errs.rs new file mode 100644 index 0000000..2c83744 --- /dev/null +++ b/src/errs.rs @@ -0,0 +1,64 @@ +use std::error::Error; +use std::fmt::{self, Display, Formatter}; + +#[derive(Debug)] +pub struct CharNotFoundInBase { + pub base: String, + pub c: char, +} + +impl Display for CharNotFoundInBase { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "char '{}' not found in base '{}'", self.c, self.base) + } +} + +impl Error for CharNotFoundInBase {} + +#[derive(Debug)] +pub struct ConversionOverflow { + pub base: String, + pub baselen: usize, + pub power: u32, +} + +impl Display for ConversionOverflow { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!( + f, + "base '{}' of length {} ** {} overflowed", + self.base, self.baselen, self.power + ) + } +} + +impl Error for ConversionOverflow {} + +#[derive(Debug)] +pub struct BaseLenTooShort(pub String); + +impl Display for BaseLenTooShort { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "base '{}' length must be at least be 2", self.0,) + } +} + +impl Error for BaseLenTooShort {} + +#[derive(Debug)] +pub struct DuplicateCharInBase { + pub base: String, + pub c: char, +} + +impl Display for DuplicateCharInBase { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!( + f, + "base '{}' has at least 2 occurences of char '{}'", + self.base, self.c + ) + } +} + +impl Error for DuplicateCharInBase {} diff --git a/src/lib.rs b/src/lib.rs index 13ed16f..55b29d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod errs; use std::error::Error; pub static BASE2: &str = "01"; @@ -5,20 +6,16 @@ pub static BASE8: &str = "01234567"; pub static BASE10: &str = "0123456789"; pub static BASE16: &str = "0123456789ABCDEF"; -fn check_base(base: &str) -> Result<(), String> { +fn check_base(base: &str) -> Result<(), Box> { if base.len() < 2 { - return Err(format!( - "base length should be at least 2: '{}'.len() -> {}", - base, - base.len() - )); + return Err(Box::new(errs::BaseLenTooShort(String::from(base)))); } for c in base.chars() { if base.chars().filter(|c2| &c == c2).count() > 1 { - return Err(format!( - "base must have unique characters: '{}' has multiple '{}'", - base, c, - )); + return Err(Box::new(errs::DuplicateCharInBase { + base: String::from(base), + c, + })); } } Ok(()) @@ -29,19 +26,25 @@ pub fn base_to_decimal(nbr: &str, from_base: &str) -> Result(|| format!("char '{}' not found in base '{}'", c, from_base))?; + let x = from_base.chars().position(|x| x == c).ok_or_else(|| { + Box::new(errs::CharNotFoundInBase { + c, + base: String::from(from_base), + }) + })?; result += x * baselen .checked_pow(i) - .ok_or_else(|| format!("baselen {} ** {} overflowed", baselen, i))? as usize; + .ok_or_else(|| errs::ConversionOverflow { + base: String::from(from_base), + baselen, + power: i, + })? as usize; } Ok(result) } -pub fn decimal_to_base(mut x: usize, to_base: &str) -> Result { +pub fn decimal_to_base(mut x: usize, to_base: &str) -> Result> { check_base(to_base)?; if x == 0 { return Ok(String::from("0")); diff --git a/src/main.rs b/src/main.rs index a4e5aff..e0ab396 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,6 @@ fn main() { let to_base = matches.value_of("TO_BASE").unwrap(); match base_to_base(number, from_base, to_base) { Ok(result) => println!("{}", result), - Err(err) => println!("{:?}", err), + Err(err) => println!("Error: {}", err), } }