diff --git a/src/builtin.rs b/src/builtin.rs index 8175425..aa1796d 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -3,6 +3,69 @@ use std::process::Command; use crate::swaybar_object::SwaybarObject; use regex::Regex; +#[derive(Debug)] +pub enum Error { + Generic(String), + Regex(regex::Error), + ParseInt(std::num::ParseIntError), + IO(std::io::Error), + FromUTF8(std::string::FromUtf8Error), +} + +impl From for Error { + fn from(string: String) -> Self { + Error::Generic(string) + } +} + +impl From for Error { + fn from(error: regex::Error) -> Self { + Error::Regex(error) + } +} + +impl From for Error { + fn from(error: std::num::ParseIntError) -> Self { + Error::ParseInt(error) + } +} + +impl From for Error { + fn from(error: std::io::Error) -> Self { + Error::IO(error) + } +} + +impl From for Error { + fn from(error: std::string::FromUtf8Error) -> Self { + Error::FromUTF8(error) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Error::Generic(s) => f.write_str(s), + Error::Regex(e) => e.fmt(f), + Error::ParseInt(e) => e.fmt(f), + Error::IO(e) => e.fmt(f), + Error::FromUTF8(e) => e.fmt(f), + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::Generic(_) => None, + Error::Regex(e) => e.source(), + Error::ParseInt(e) => e.source(), + Error::IO(e) => e.source(), + Error::FromUTF8(e) => e.source(), + } + } +} + #[derive(Debug)] pub struct BattInfo { regex: Regex, @@ -23,13 +86,14 @@ impl BattInfo { self.acpi_error } - pub fn update(&mut self, object: &mut SwaybarObject) -> Result<(), ()> { + pub fn update(&mut self, object: &mut SwaybarObject) -> Result<(), Error> { if self.acpi_error { - return Err(()); + return Err(Error::Generic("battinfo: in error state".into())); } let output_string: String; let output_percentage: u8; - if let Ok(string) = self.get_acpi_string() { + let string_result = self.get_acpi_string(); + if let Ok(string) = string_result { (output_string, output_percentage) = string; let percentage: f32 = output_percentage as f32 / 100.0f32; @@ -50,52 +114,37 @@ impl BattInfo { Ok(()) } else { self.acpi_error = true; - Err(()) + string_result.map(|_| ()) } } - fn get_acpi_string(&mut self) -> Result<(String, u8), ()> { + fn get_acpi_string(&mut self) -> Result<(String, u8), Error> { if self.acpi_error { - return Err(()); + return Err(Error::Generic("battinfo: acpi_error is true".into())); } let mut cmd_builder = Command::new("acpi"); cmd_builder.arg("-b"); - let output_result = cmd_builder.output(); - if let Ok(output_unwrapped) = output_result { - let string_result = String::from_utf8(output_unwrapped.stdout); - if let Ok(string) = string_result { - let regex_captures_result = self.regex.captures(&string); - if regex_captures_result.is_none() { - self.acpi_error = true; - return Err(()); - } - let regex_captures = regex_captures_result.unwrap(); - let full_result = regex_captures.get(0); - if full_result.is_none() { - self.acpi_error = true; - return Err(()); - } - let full_string = full_result.unwrap().as_str().to_owned(); - let percentage_result = regex_captures.get(1); - if percentage_result.is_none() { - self.acpi_error = true; - return Err(()); - } - let percentage_result = percentage_result.unwrap().as_str().parse::(); - if percentage_result.is_err() { - self.acpi_error = true; - return Err(()); - } - let percentage: u8 = percentage_result.unwrap(); - - Ok((full_string, percentage)) - } else { - self.acpi_error = true; - Err(()) - } - } else { + let output = cmd_builder.output()?; + let string = String::from_utf8(output.stdout)?; + let regex_captures_result = self.regex.captures(&string); + if regex_captures_result.is_none() { self.acpi_error = true; - Err(()) + return Err(Error::Generic("battinfo: regex captured nothing".into())); } + let regex_captures = regex_captures_result.unwrap(); + let full_result = regex_captures.get(0); + if full_result.is_none() { + self.acpi_error = true; + return Err(Error::Generic("battinfo: no full regex capture".into())); + } + let full_string = full_result.unwrap().as_str().to_owned(); + let percentage_result = regex_captures.get(1); + if percentage_result.is_none() { + self.acpi_error = true; + return Err(Error::Generic("battinfo: no regex capture 1".into())); + } + let percentage: u8 = percentage_result.unwrap().as_str().parse::()?; + + Ok((full_string, percentage)) } }