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}
}
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 {
cur.types[cur.length] = list1[i];
cur.length += 1;
i += 1;
j += 1;
}
}
while i < a.length {
cur.types[cur.length] = list1[i];
cur.length += 1;
i += 1;
}
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;
}
}
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;
}
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
}
}
)
);
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
}
}