#![no_std]
#![forbid(unsafe_code)]
#[macro_export]
macro_rules! hierarchy {
($($root:ty $({
$($child:ty $({
$($grandchildren_parsed_recursively:tt)*
})?),* $(,)?
})?),* $(,)?) => {
$($(
$crate::hierarchy!{
$($child $({
$($grandchildren_parsed_recursively)*
})?),*
}
$($(
$crate::__hierarchy_internals!{
[$root][$child][
$($grandchildren_parsed_recursively)*
]
}
)?)*
)?)*
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __hierarchy_internals {
([$root:ty][$child:ty][
$($grandchild:ty $({
$($further:tt)*
})?),* $(,)?
]) => {
$(
$($crate::__hierarchy_internals!{
[$root][$child][
$($further)*
]
})?
impl ::core::convert::From<$grandchild> for $root {
fn from(g: $grandchild) -> Self {
<$root>::from(<$child>::from(g))
}
}
)*
};
}
#[cfg(test)]
mod test {
#![allow(unused)]
pub enum GlobalError {
Shape(ShapeError),
Color(ColorError),
}
impl From<ShapeError> for GlobalError {
fn from(e: ShapeError) -> Self {
Self::Shape(e)
}
}
impl From<ColorError> for GlobalError {
fn from(e: ColorError) -> Self {
Self::Color(e)
}
}
pub enum ShapeError {
Circle(CircleError),
Rectangle(RectangleError),
}
impl From<CircleError> for ShapeError {
fn from(e: CircleError) -> Self {
Self::Circle(e)
}
}
impl From<RectangleError> for ShapeError {
fn from(e: RectangleError) -> Self {
Self::Rectangle(e)
}
}
pub struct CircleError {
msg: &'static str,
radius: f64,
}
pub enum RectangleError {
Square(SquareError),
ArbitraryRectangleError { msg: &'static str, a: f64, b: f64 },
}
impl From<SquareError> for RectangleError {
fn from(e: SquareError) -> Self {
Self::Square(e)
}
}
pub struct SquareError {
msg: &'static str,
a: f64,
}
pub enum ColorError {
Red(RedError),
Blue(BlueError),
}
impl From<RedError> for ColorError {
fn from(e: RedError) -> Self {
Self::Red(e)
}
}
impl From<BlueError> for ColorError {
fn from(e: BlueError) -> Self {
Self::Blue(e)
}
}
pub struct RedError {
msg: &'static str,
}
pub struct BlueError {
msg: &'static str,
}
crate::hierarchy! {
GlobalError {
ShapeError {
CircleError,
RectangleError { SquareError },
},
ColorError { RedError, BlueError }
}
}
fn foo() -> Result<(), SquareError> {
Err(SquareError {
msg: "hello world",
a: 42.0,
})
}
fn bar() -> Result<(), GlobalError> {
foo()?;
Ok(())
}
#[test]
fn conversion_test() {
bar().err().unwrap();
}
}