error_union 0.2.0

A library to simplify error handling in Rust
Documentation
use std::any::Any;
use std::fmt::{Debug, Formatter, Pointer};
use crate::internal::*;

use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};


pub type ErrorId = u128;
const MAXSIZE : usize = 128;
pub struct ErrorSubtract<A,B>(PhantomData<A>, PhantomData<B>);
impl<A : GetErrorSet, B : GetErrorSet> GetErrorSet for ErrorSubtract<A,B>
{
    const COLLECTION: ErrorSet = ErrorSet::subtract(A::COLLECTION, B::COLLECTION);
}
#[derive(Copy, Clone, Debug, Eq, PartialOrd, Ord, PartialEq)]
pub struct ErrorWrapper
{
    pub id : u128,
    pub type_name : &'static str
}
#[derive(Copy, Clone, Debug, Eq, PartialOrd, Ord, PartialEq)]
pub struct ErrorSet
{
    pub length : usize,
    pub types : [ErrorWrapper; 128]
}

impl ErrorSet
{
    pub const fn new_from_type<T : HasErrorId>() -> ErrorSet
    {
        let mut arr = [ErrorWrapper {id : 0, type_name : ""}; MAXSIZE];
        arr[0] = ErrorWrapper {id : T::ERROR_ID, type_name : T::ERROR_STR};
        ErrorSet {length : 1, types : arr}

    }
    //<A : GetErrorSet, B : GetErrorSet>
    pub const fn new_from_multiple_children(arg : &[ErrorSet]) -> ErrorSet
    {
        let mut sum = ErrorSet {length : 0, types : [ErrorWrapper {id : 0, type_name : ""}; MAXSIZE]};
        let mut i = 0;
        while i < arg.len()
        {
            sum = Self::new_from_children(sum, arg[i]);
            i += 1;
        }
        sum
    }
    pub const fn new_from_children(a : ErrorSet, b : ErrorSet) -> ErrorSet
    {
        let list1 = &a.types;
        let list2 = &b.types;
        let mut i = 0;
        let mut j = 0;
        let mut cur = ErrorSet {length : 0, types : [ErrorWrapper {id : 0, type_name : ""}; MAXSIZE]};
        while i < a.length && j < b.length {
            if list1[i].id > list2[j].id {
                cur.types[cur.length] = list1[i];
                cur.length += 1;
                i += 1;
            } else if list1[i].id < list2[j].id {
                cur.types[cur.length] = list2[j];
                cur.length += 1;
                j += 1;
            } else {
                // If elements are equal, only push one of them
                cur.types[cur.length] = list1[i];
                cur.length += 1;
                i += 1;
                j += 1;
            }
        }

        // Add remaining elements from list1
        while i < a.length {
            cur.types[cur.length] = list1[i];
            cur.length += 1;
            i += 1;
        }

        // Add remaining elements from list2
        while j < b.length {
            cur.types[cur.length] = list2[j];
            cur.length += 1;
            j += 1;
        }

        cur
    } //
    pub const fn subset<A : GetErrorSet, B : GetErrorSet>() -> bool
    {
        let mut i = 0;
        let mut j = 0;
        let a = A::COLLECTION;
        let list1 = &a.types;
        let b = B::COLLECTION;
        let list2 = &b.types;
        while i < a.length {
            if j >= b.length
            {
                return false;
            }
            if list1[i].id > list2[j].id {
                return false
            } else if list1[i].id < list2[j].id {
                j += 1;
            } else {
                i += 1;
                j += 1;
            }
        }
        true
    }
    pub const fn subtract(a : ErrorSet, b : ErrorSet) -> ErrorSet
    {
        let list1 = &a.types;
        let list2 = &b.types;
        let mut i = 0;
        let mut j = 0;
        let mut cur = ErrorSet {length : 0, types : [ErrorWrapper {id : 0, type_name : ""}; MAXSIZE]};
        while i < a.length && j < b.length {
            if list1[i].id > list2[j].id {
                cur.types[cur.length] = list1[i];
                cur.length += 1;
                i += 1;
            } else if list1[i].id < list2[j].id {
                j += 1;
            } else {
                i += 1;
                j += 1;
            }
        }

        // Add remaining elements from list1
        while i < a.length {
            cur.types[cur.length] = list1[i];
            cur.length += 1;
            i += 1;
        }

        cur
    }

}



pub trait HasErrorId
{
    const ERROR_ID : ErrorId;
    const ERROR_STR : &'static str;
}
impl GetErrorSet for ()
{
    const COLLECTION: ErrorSet = ErrorSet { length: 0, types: [ErrorWrapper {id : 0, type_name : ""}; MAXSIZE]};
}
impl<A : GetErrorSet> GetErrorSet for (A,)
{
    const COLLECTION : ErrorSet = A::COLLECTION;
}
impl<A : GetErrorSet, B : GetErrorSet> GetErrorSet for (A, B)
{
    const COLLECTION : ErrorSet = ErrorSet::new_from_children(A::COLLECTION, B::COLLECTION);
}

pub trait MapEveryError<Func, ReturnType>
{
    fn map_every_internal(id : ErrorId, data : &Box<dyn Any>, func : &Func) -> Option<ReturnType> where Self : Sized;
    //fn map_every_as_error_internal(id : ErrorId, data : &Box<dyn Any>, func : &Func);
}
impl<Func, A : MapEveryError<Func, ReturnType>, B, ReturnType > MapEveryError<Func, ReturnType> for ErrorSubtract<A,B>
{
    fn map_every_internal(id: ErrorId, data: &Box<dyn Any>, func: &Func) -> Option<ReturnType> where Self: Sized {
        if let Some(val) = A::map_every_internal(id, data, func)
        {
            return Some(val);
        }
        None
    }

}
impl<Func, A : MapEveryError<Func, ReturnType>, B : MapEveryError<Func, ReturnType>, ReturnType > MapEveryError<Func, ReturnType> for (A, B)
{
    fn map_every_internal(id: ErrorId, data: &Box<dyn Any>, func: &Func) -> Option<ReturnType> where Self: Sized {
        if let Some(val) = A::map_every_internal(id, data, func)
        {
            return Some(val);
        }
        if let Some(val) = B::map_every_internal(id, data, func)
        {
            return Some(val);
        }
        None
    }

}
impl<Func : Fn(&A) -> ReturnType, ReturnType, A : HasErrorId + 'static>  MapEveryError<Func, ReturnType> for A
{
    fn map_every_internal(id: ErrorId, data: &Box<dyn Any>, func: &Func) -> Option<ReturnType> where Self: Sized {
        if A::ERROR_ID == id
        {
            let s : &Self = data.downcast_ref().unwrap();
            Some(func(s))
        } else {
            None
        }
    }
}
#[macro_export]
macro_rules! implement_tuple(
    ($($i : ident)+) => (
        impl<$($i : GetErrorSet,)+> GetErrorSet for ($($i,)+)
        {
            const COLLECTION: ErrorSet = ErrorSet::new_from_multiple_children(&[$($i::COLLECTION,)+]);
        }
        impl<Func, $($i : MapEveryError<Func, ReturnType>, )+ ReturnType> MapEveryError<Func, ReturnType> for ($($i,)+)
        {
            fn map_every_internal(id: ErrorId, data: &Box<dyn Any>, func: &Func) -> Option<ReturnType> where Self: Sized {
                $(
                    if let Some(val) = $i::map_every_internal(id, data, func)
                    {
                        return Some(val);
                    }
                )+
                None
            }

        }
    )
);
/*
python script:
for i in range(3,24):
    line = "implement_tuple!(T0"
    for j in range(1,i):
        line += " T" + str(j)
    line += ");"
    print (line)

*/
implement_tuple!(T0 T1 T2);
implement_tuple!(T0 T1 T2 T3);
implement_tuple!(T0 T1 T2 T3 T4);
implement_tuple!(T0 T1 T2 T3 T4 T5);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18 T19);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18 T19 T20);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18 T19 T20 T21);
implement_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18 T19 T20 T21 T22);
impl<T : HasErrorId> GetErrorSet for T
{
    const COLLECTION: ErrorSet = ErrorSet::new_from_type::<T>();
}

pub trait GetErrorSet
{
    const COLLECTION : ErrorSet;
    fn get_error_set(&self) -> ErrorSet
    {
        Self::COLLECTION
    }
}