Rust code shared from the playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::error::Error; | |
use std::fmt; | |
/// Non-critical shopping error (warning). | |
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum ShoppingWarning { | |
Dirty(u8), | |
Broken, | |
} | |
impl fmt::Display for ShoppingWarning { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
match *self { | |
ShoppingWarning::Dirty(level) => { | |
write!(f, "Item is dirty (level={})", level) | |
}, | |
_ => write!(f, "{}", self.description()), | |
} | |
} | |
} | |
impl Error for ShoppingWarning { | |
fn description(&self) -> &str { | |
match *self { | |
ShoppingWarning::Dirty(_) => "Item is dirty", | |
ShoppingWarning::Broken => "Item is broken", | |
} | |
} | |
} | |
/// (Potentially) critical shopping error. | |
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
pub enum ShoppingError { | |
SoldOut, | |
ShopClosed, | |
NotEnoughMoney, | |
/// Treat warning as critical. | |
Warning(ShoppingWarning), | |
} | |
impl fmt::Display for ShoppingError { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
match *self { | |
ShoppingError::Warning(ref w) => w.fmt(f), | |
_ => write!(f, "{}", self.description()), | |
} | |
} | |
} | |
impl Error for ShoppingError { | |
fn description(&self) -> &str { | |
match *self { | |
ShoppingError::SoldOut => "Sold out, no items", | |
ShoppingError::ShopClosed => "Shop is closed", | |
ShoppingError::NotEnoughMoney => "You should have more money", | |
ShoppingError::Warning(ref w) => w.description(), | |
} | |
} | |
fn cause(&self) -> Option<&Error> { | |
match *self { | |
ShoppingError::Warning(ref w) => Some(w), | |
_ => None, | |
} | |
} | |
} | |
impl From<ShoppingWarning> for ShoppingError { | |
fn from(w: ShoppingWarning) -> Self { | |
ShoppingError::Warning(w) | |
} | |
} | |
fn buy<F>(item_id: u32, amount: usize, mut warning_handler: F) | |
-> Result<usize, ShoppingError> | |
where | |
F: FnMut(ShoppingWarning) -> Result<(), ShoppingWarning>, | |
{ | |
buy_impl(item_id, amount, &mut warning_handler) | |
} | |
/// Attempts to buy `amount`-number of items indicated by `item_id`. | |
/// | |
/// * 0: sold out | |
/// * 1: 1 item and 1 dirty (level 2) item. | |
/// * 2: 1 dirty item (level 5) and 1 broken item. | |
fn buy_impl<F>(item_id: u32, amount: usize, warning_handler: &mut F) | |
-> Result<usize, ShoppingError> | |
where | |
F: FnMut(ShoppingWarning) -> Result<(), ShoppingWarning>, | |
{ | |
match item_id { | |
0 => { | |
if amount == 0 { | |
Ok(0) | |
} else { | |
Err(ShoppingError::SoldOut) | |
} | |
}, | |
1 => { | |
match amount { | |
0 | 1 => Ok(0), | |
2 => { | |
warning_handler(ShoppingWarning::Dirty(2))?; | |
Ok(2) | |
}, | |
_ => Err(ShoppingError::SoldOut), | |
} | |
}, | |
2 => { | |
if amount >= 3 { | |
return Err(ShoppingError::SoldOut); | |
} | |
if amount >= 1 { | |
warning_handler(ShoppingWarning::Dirty(5))?; | |
if amount >= 2 { | |
warning_handler(ShoppingWarning::Broken)?; | |
} | |
} | |
Ok(amount) | |
}, | |
_ => Err(ShoppingError::SoldOut), | |
} | |
} | |
fn main() { | |
// Buy any items. | |
assert_eq!( | |
Err(ShoppingError::SoldOut), | |
buy(0, 1, |_| Ok(())) | |
); | |
// Buy only clean and not broken items. | |
assert_eq!( | |
Err(ShoppingError::Warning(ShoppingWarning::Dirty(2))), | |
buy(1, 2, |w| Err(w)) | |
); | |
// Buy not broken items, allow dirty items. | |
assert_eq!( | |
Ok(2), | |
buy(1, 2, |w| { | |
if let ShoppingWarning::Broken = w { | |
Err(w) | |
} else { | |
Ok(()) | |
} | |
}) | |
); | |
// Buy not broken items, allow dirty items. | |
assert_eq!( | |
Err(ShoppingError::Warning(ShoppingWarning::Broken)), | |
buy(2, 2, |w| { | |
if let ShoppingWarning::Broken = w { | |
Err(w) | |
} else { | |
Ok(()) | |
} | |
}) | |
); | |
// Buy not broken items, allow dirty items. | |
// Log troubles. | |
let mut troubles = Vec::new(); | |
assert_eq!( | |
Err(ShoppingError::Warning(ShoppingWarning::Broken)), | |
buy(2, 2, |w| { | |
troubles.push(w.clone()); | |
if let ShoppingWarning::Broken = w { | |
Err(w) | |
} else { | |
Ok(()) | |
} | |
}) | |
); | |
assert_eq!( | |
troubles, | |
vec![ | |
ShoppingWarning::Dirty(5), | |
ShoppingWarning::Broken, | |
] | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment