Skip to content

Commit

Permalink
Refactor errors
Browse files Browse the repository at this point in the history
  • Loading branch information
ctison committed Mar 31, 2020
1 parent fa26b0b commit 55ad856
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 17 deletions.
64 changes: 64 additions & 0 deletions src/errs.rs
Original file line number Diff line number Diff line change
@@ -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 {}
35 changes: 19 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
mod errs;
use std::error::Error;

pub static BASE2: &str = "01";
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<dyn Error>> {
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(())
Expand All @@ -29,19 +26,25 @@ pub fn base_to_decimal(nbr: &str, from_base: &str) -> Result<usize, Box<dyn Erro
let baselen = from_base.len();
let mut result: usize = 0;
for (c, i) in nbr.chars().zip((0..nbr.chars().count() as u32).rev()) {
let x = from_base
.chars()
.position(|x| x == c)
.ok_or_else::<String, _>(|| 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<String, String> {
pub fn decimal_to_base(mut x: usize, to_base: &str) -> Result<String, Box<dyn Error>> {
check_base(to_base)?;
if x == 0 {
return Ok(String::from("0"));
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}

0 comments on commit 55ad856

Please sign in to comment.