error_union 0.2.0

A library to simplify error handling in Rust
Documentation
use const_panic::PanicVal;
use crate::internal::*;

pub const fn generate_msg_for_match_err<A : GetErrorSet,B : GetErrorSet>(ignore_unthrown : bool) -> Option<Message>
{
    let uncaught = ErrorSet::subtract(A::COLLECTION, B::COLLECTION);
    let unnecessary = ErrorSet::subtract(B::COLLECTION, A::COLLECTION);
    let mut message = Message::new();
    let mut error : bool = false;
    if uncaught.length != 0 && (!ignore_unthrown)
    {
        message = message.append_str("Uncaught errors: ");
        message = message.append_error_set(uncaught);
        error = true;
    }
    if uncaught.length != 0 && unnecessary.length != 0 && (!ignore_unthrown)
    {
        message = message.append_str(". ");
    }
    if unnecessary.length != 0
    {
        message = message.append_str("Unnecessary caught errors: ");
        message = message.append_error_set(unnecessary);
        error = true;
    }
    if error {
        Some(message)
    } else {
        None
    }
}
#[macro_export]
macro_rules! into_err {
    ($e : expr) => {$e.map_err(|u|{
        use ::error_union::internal::WrapError;
        u.wrap_error().map(|u|{
            fn internal<Input : ::error_union::internal::GetErrorSet,Output : ::error_union::internal::GetErrorSet>(input : ::error_union::internal::Error<Input>) -> ::error_union::internal::Error<Output>
            {
                struct Holder<A : ::error_union::internal::GetErrorSet,B : ::error_union::internal::GetErrorSet>(::std::marker::PhantomData<A>, ::std::marker::PhantomData<B>);
                impl<A : ::error_union::internal::GetErrorSet,B : ::error_union::internal::GetErrorSet> Holder<A,B>
                {
                    const ASSERT: bool = {
                        let missing = ::error_union::internal::ErrorSet::subtract(A::COLLECTION, B::COLLECTION);
                        if missing.length != 0
                        {
                            let mut msg = ::error_union::internal::Message::new();
                            msg = msg.append_str("Tried to propagate errors not in function return: ");
                            msg = msg.append_error_set(missing);
                            ::error_union::internal::concat_panic(&[&msg.message]);
                        } else {
                            false
                        }   
                    };
                }
                if Holder::<Input, Output>::ASSERT
                {
                    unreachable!()
                }
                input.into_err_unchecked()
            }
            internal(u)
        })})};

}
#[macro_export]
macro_rules! as_true {
    ($($t : tt)*) => {true}
}

#[macro_export]
macro_rules! match_err {
    ($e:expr, Ok($ok_ident : ident) => $ok_arm : expr, $($err_i : ident $(: $err_type : ty => $err_arm : expr)?  $(=> $err_guard: expr)? ,)*) =>
    {
        const HAS_UNDERSCORE : bool = false $($(| as_true!($err_guard))*)*;
        type CaughtErrors = ($($($err_type,)*)*);
        fn internal<Input : ::error_union::internal::GetErrorSet, OkType>(_ : &Result<OkType, ::error_union::internal::Error<Input>>)
        {
            struct Holder<A : ::error_union::internal::GetErrorSet,B : ::error_union::internal::GetErrorSet>(::std::marker::PhantomData<A>, ::std::marker::PhantomData<B>);
            impl<A : ::error_union::internal::GetErrorSet,B : ::error_union::internal::GetErrorSet> Holder<A,B>
            {
                const ASSERT: bool = {
                    if let Some(msg) = ::error_union::internal::generate_msg_for_match_err::<A,B>(HAS_UNDERSCORE)
                    {
                        ::error_union::internal::concat_panic(&[&msg.message])
                    } else {
                        false
                    }
                };
            }
            if Holder::<Input, CaughtErrors>::ASSERT
            {
                unreachable!();
            }
        }
        let temp = $e;
        internal(&temp);
        match temp {
            Ok($ok_ident) => { $ok_arm },
            Err(error) =>
                {
                    match error.1 {
                        $(
                            $(
                            <$err_type>::ERROR_ID => {
                                    if ::std::any::TypeId::of::<$err_type>() == error.2.type_id()
                                    {
                                        if let Ok($err_i) = error.2.downcast::<$err_type>()
                                        {
                                            $err_arm
                                        } else {
                                            panic!("Failed to downcast despite type id match");
                                        }
                                    } else {
                                        panic!("Error id matched in match err arm, but type id check failed");
                                    }
                            }, )*
                            $(
                            _ => {
                                //ignore!($err_guard);
                               let $err_i = error.subtract_errors::<CaughtErrors>();
                                $err_guard
                            },)*
                        )*
                        _ => todo!(),
                    }
                }
        
        } 


    }

}