use super::*; use std::{ io::{self,}, fmt, error, num::NonZeroUsize, }; #[derive(Debug)] pub enum ErrorLocation { Oneesan, Imouto, Internal, } #[derive(Debug)] pub struct Error { explination: String, bytes_done: Option, location: ErrorLocation, inner: Option, } fn clamp(value: i64, min: i64, max: i64) -> i64 { if value < min { min } else if value > max { max } else { value } } fn human_bytes(bytes: usize) -> String { const POSTFIXES: [&'static str; 7] = ["b", "kb", "mb", "gb", "tb", "pb", "eb"]; if bytes == 0 { return format!("0 {}", POSTFIXES[0]); } let idx = (bytes as f64).log(1024f64).floor() as i64; let suf = &POSTFIXES[clamp(idx, 0, 6) as usize]; let num = (1024_i64).pow(idx as u32); format!("{:.2} {}", num, suf) } impl Error { pub fn new(expl: String, from: ErrorLocation, bytes_done: usize) -> Self { Self { explination: expl, location: from, inner: None, bytes_done: NonZeroUsize::new(bytes_done), } } } impl From for Error { fn from(f: io::Error) -> Self { Self { explination: format!("i/o error: "), location: ErrorLocation::Internal, bytes_done: None, inner: Some(f), } } } impl fmt::Display for ErrorLocation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ErrorLocation::Oneesan => write!(f, ""), ErrorLocation::Imouto => write!(f, ""), _ => write!(f, ""), } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}+{}: {}{}", self.location, match &self.bytes_done { Some(value) => human_bytes(value.get()), None => "0 b".to_owned(), }, self.explination, match &self.inner { Some(inner) => format!(" {}", inner), None => "".to_owned(), }) } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match &self.inner { Some(x) => Some(x), None => None, } } } pub(super) trait WeebExt { fn into_imouto(self) -> Error; fn into_oneesan(self) -> Error; } pub(super) trait TryWeebExt { fn try_imouto(self, bytes_done: usize) -> Result; fn try_oneesan(self, bytes_done: usize) -> Result; } impl WeebExt for io::Error { fn into_imouto(self) -> Error { Error { location: ErrorLocation::Imouto, ..Error::from(self) } } fn into_oneesan(self) -> Error { Error { location: ErrorLocation::Oneesan, ..Error::from(self) } } } impl TryWeebExt for io::Result { fn try_imouto(self, bytes_done: usize) -> Result { match self { Ok(v) => Ok(v), Err(e) => Err(Error { bytes_done: NonZeroUsize::new(bytes_done), ..e.into_imouto() }), } } fn try_oneesan(self, bytes_done: usize) -> Result { match self { Ok(v) => Ok(v), Err(e) => Err(Error { bytes_done: NonZeroUsize::new(bytes_done), ..e.into_oneesan() }), } } }