diff --git a/Cargo.toml b/Cargo.toml index 5e8b075..77a2d3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,10 @@ categories = ["data-structures", "parsing"] repository = "https://github.com/openrr/urdf-rs" documentation = "http://docs.rs/urdf-rs" +# Note: serde is public dependency. [dependencies] -serde-xml-rs = "0.4.0" -serde = { version = "1.0.118", features = ["derive"] } -RustyXML = "0.3.0" regex = "1.4.2" +RustyXML = "0.3.0" +serde = { version = "1.0.118", features = ["derive"] } +serde-xml-rs = "0.4.0" +thiserror = "1.0.7" diff --git a/src/errors.rs b/src/errors.rs index 512b764..795ef9c 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,58 +1,54 @@ -use std::error::Error; -use std::fmt; -use std::string; - -#[derive(Debug)] -pub enum UrdfError { - File(::std::io::Error), - Xml(::serde_xml_rs::Error), - RustyXml(::xml::BuilderError), - Parse(String), +use thiserror::Error; + +/// Alias for a `Result` with the error type `UrdfError`. +pub type Result = std::result::Result; + +#[derive(Debug, Error)] +#[error(transparent)] +pub struct UrdfError(#[from] ErrorKind); + +// Hiding error variants from a library's public error type to prevent +// dependency updates from becoming breaking changes. +// We can add `UrdfErrorKind` enum or `is_*` methods that indicate the kind of +// error if needed, but don't expose dependencies' types directly in the +// public API. +#[derive(Debug, Error)] +pub(crate) enum ErrorKind { + #[error(transparent)] + File(#[from] std::io::Error), + #[error(transparent)] + Xml(#[from] serde_xml_rs::Error), + #[error(transparent)] + RustyXml(#[from] xml::BuilderError), + #[error("command error {}", .0)] Command(String), } -pub type Result = ::std::result::Result; - -impl fmt::Display for UrdfError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - UrdfError::File(ref err) => err.fmt(f), - UrdfError::Xml(ref err) => err.fmt(f), - UrdfError::RustyXml(ref err) => err.fmt(f), - UrdfError::Parse(ref msg) => write!(f, "parse error {}", msg), - UrdfError::Command(ref msg) => write!(f, "command error {}", msg), - } +impl UrdfError { + pub(crate) fn new(err: impl Into) -> Self { + Self(err.into()) } } -impl Error for UrdfError {} - impl From for UrdfError { fn from(err: std::io::Error) -> UrdfError { - UrdfError::File(err) - } -} - -impl From for UrdfError { - fn from(err: serde_xml_rs::Error) -> UrdfError { - UrdfError::Xml(err) + ErrorKind::File(err).into() } } -impl From for UrdfError { - fn from(err: xml::BuilderError) -> UrdfError { - UrdfError::RustyXml(err) +impl From<&str> for UrdfError { + fn from(err: &str) -> UrdfError { + ErrorKind::Command(err.to_owned()).into() } } -impl<'a> From<&'a str> for UrdfError { - fn from(err: &'a str) -> UrdfError { - UrdfError::Command(err.to_owned()) +impl From for UrdfError { + fn from(err: std::string::FromUtf8Error) -> UrdfError { + ErrorKind::Command(err.to_string()).into() } } -impl From for UrdfError { - fn from(err: string::FromUtf8Error) -> UrdfError { - UrdfError::Command(err.to_string()) - } -} +// Note: These implementations are intentionally not-exist to prevent dependency +// updates from becoming breaking changes. +// impl From for UrdfError +// impl From for UrdfError diff --git a/src/funcs.rs b/src/funcs.rs index afa1556..ebcc725 100644 --- a/src/funcs.rs +++ b/src/funcs.rs @@ -5,7 +5,7 @@ use std::path::Path; /// sort and to avoid the [issue](https://github.com/RReverser/serde-xml-rs/issues/5) fn sort_link_joint(string: &str) -> Result { - let e: xml::Element = string.parse()?; + let e: xml::Element = string.parse().map_err(UrdfError::new)?; let mut links = Vec::new(); let mut joints = Vec::new(); let mut materials = Vec::new(); @@ -94,7 +94,7 @@ pub fn read_file>(path: P) -> Result { pub fn read_from_string(string: &str) -> Result { let sorted_string = sort_link_joint(string)?; - serde_xml_rs::from_str(&sorted_string).map_err(From::from) + serde_xml_rs::from_str(&sorted_string).map_err(UrdfError::new) } #[test] diff --git a/src/utils.rs b/src/utils.rs index b660fec..b24023a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -25,7 +25,7 @@ where if output.status.success() { Ok(String::from_utf8(output.stdout)?) } else { - Err(UrdfError::Command("faild to xacro".to_owned())) + Err(ErrorKind::Command("faild to xacro".to_owned()).into()) } } @@ -73,7 +73,7 @@ where read_file(&input_path) } } else { - return Err(UrdfError::Command("failed to get extension".to_owned())); + Err(ErrorKind::Command("failed to get extension".to_owned()).into()) } }