use core::marker::PhantomData;
use core::ptr::NonNull;
use crate::{CcBox, Mark};
pub(crate) trait ListMethods: Sized {
    #[cfg(all(test, feature = "std"))] fn first(&self) -> Option<NonNull<CcBox<()>>>;
    fn add(&mut self, ptr: NonNull<CcBox<()>>);
    fn remove(&mut self, ptr: NonNull<CcBox<()>>);
    fn remove_first(&mut self) -> Option<NonNull<CcBox<()>>>;
    fn is_empty(&self) -> bool;
    #[inline]
    #[cfg(any(feature = "pedantic-debug-assertions", all(test, feature = "std")))] fn contains(&self, ptr: NonNull<CcBox<()>>) -> bool {
        self.iter().any(|elem| elem == ptr)
    }
    fn iter(&self) -> Iter;
    #[cfg(all(test, feature = "std"))] fn into_iter(self) -> ListIter<Self>;
}
pub(crate) struct List {
    first: Option<NonNull<CcBox<()>>>,
}
impl List {
    #[inline]
    pub(crate) const fn new() -> List {
        List { first: None }
    }
}
impl ListMethods for List {
    #[inline]
    #[cfg(all(test, feature = "std"))] fn first(&self) -> Option<NonNull<CcBox<()>>> {
        self.first
    }
    #[inline]
    fn add(&mut self, ptr: NonNull<CcBox<()>>) {
        if let Some(first) = &mut self.first {
            unsafe {
                *first.as_ref().get_prev() = Some(ptr);
                *ptr.as_ref().get_next() = Some(*first);
                debug_assert!((*ptr.as_ref().get_prev()).is_none());
            }
            *first = ptr;
        } else {
            self.first = Some(ptr);
            unsafe {
                debug_assert!((*ptr.as_ref().get_next()).is_none());
                debug_assert!((*ptr.as_ref().get_prev()).is_none());
            }
        }
    }
    #[inline]
    fn remove(&mut self, ptr: NonNull<CcBox<()>>) {
        unsafe {
            match (*ptr.as_ref().get_next(), *ptr.as_ref().get_prev()) {
                (Some(next), Some(prev)) => {
                    *next.as_ref().get_prev() = Some(prev);
                    *prev.as_ref().get_next() = Some(next);
                    *ptr.as_ref().get_next() = None;
                    *ptr.as_ref().get_prev() = None;
                },
                (Some(next), None) => {
                    *next.as_ref().get_prev() = None;
                    self.first = Some(next);
                    *ptr.as_ref().get_next() = None;
                },
                (None, Some(prev)) => {
                    *prev.as_ref().get_next() = None;
                    *ptr.as_ref().get_prev() = None;
                },
                (None, None) => {
                    self.first = None;
                },
            }
            debug_assert!((*ptr.as_ref().get_next()).is_none());
            debug_assert!((*ptr.as_ref().get_prev()).is_none());
        }
    }
    #[inline]
    fn remove_first(&mut self) -> Option<NonNull<CcBox<()>>> {
        match self.first {
            Some(first) => unsafe {
                self.first = *first.as_ref().get_next();
                if let Some(next) = self.first {
                    *next.as_ref().get_prev() = None;
                }
                *first.as_ref().get_next() = None;
                first.as_ref().counter_marker().mark(Mark::NonMarked);
                Some(first)
            },
            None => {
                None
            },
        }
    }
    #[inline]
    fn is_empty(&self) -> bool {
        self.first.is_none()
    }
    #[inline]
    fn iter(&self) -> Iter {
        self.into_iter()
    }
    #[inline]
    #[cfg(all(test, feature = "std"))] fn into_iter(self) -> ListIter<List> {
        <Self as IntoIterator>::into_iter(self)
    }
}
impl Drop for List {
    #[inline]
    fn drop(&mut self) {
        while self.remove_first().is_some() {
            }
    }
}
impl<'a> IntoIterator for &'a List {
    type Item = NonNull<CcBox<()>>;
    type IntoIter = Iter<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            next: self.first,
            _phantom: PhantomData,
        }
    }
}
impl IntoIterator for List {
    type Item = NonNull<CcBox<()>>;
    type IntoIter = ListIter<List>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        ListIter {
            list: self,
        }
    }
}
pub(crate) struct Iter<'a> {
    next: Option<NonNull<CcBox<()>>>,
    _phantom: PhantomData<&'a CcBox<()>>,
}
impl<'a> Iterator for Iter<'a> {
    type Item = NonNull<CcBox<()>>;
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        match self.next {
            Some(ptr) => {
                unsafe {
                    self.next = *ptr.as_ref().get_next();
                }
                Some(ptr)
            },
            None => {
                None
            },
        }
    }
}
pub(crate) struct ListIter<T: ListMethods> {
    list: T,
}
impl<T: ListMethods> Iterator for ListIter<T> {
    type Item = NonNull<CcBox<()>>;
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.list.remove_first()
    }
}
pub(crate) struct CountedList {
    list: List,
    size: usize,
}
impl CountedList {
    #[inline]
    pub(crate) const fn new() -> CountedList {
        CountedList {
            list: List::new(),
            size: 0,
        }
    }
    #[inline]
    pub(crate) fn size(&self) -> usize {
        self.size
    }
    #[inline]
    #[cfg(feature = "finalization")]
    pub(crate) unsafe fn mark_self_and_append(&mut self, mark: Mark, to_append: List, to_append_size: usize) {
        if let Some(mut prev) = self.list.first {
            for elem in self.list.iter() {
                unsafe {
                    elem.as_ref().counter_marker().mark(mark);
                }
                prev = elem;
            }
            unsafe {
                if let Some(ptr) = to_append.first {
                    *prev.as_ref().get_next() = to_append.first;
                    *ptr.as_ref().get_prev() = Some(prev);
                }
            }
        } else {
            self.list.first = to_append.first;
            }
        self.size += to_append_size;
        core::mem::forget(to_append); }
    #[inline]
    #[cfg(feature = "finalization")]
    pub(crate) unsafe fn swap_list(&mut self, to_swap: &mut List, to_swap_size: usize) {
        self.size = to_swap_size;
        core::mem::swap(&mut self.list, to_swap);
    }
}
impl ListMethods for CountedList {
    #[inline]
    #[cfg(all(test, feature = "std"))] fn first(&self) -> Option<NonNull<CcBox<()>>> {
        self.list.first()
    }
    #[inline]
    fn add(&mut self, ptr: NonNull<CcBox<()>>) {
        self.size += 1;
        self.list.add(ptr)
    }
    #[inline]
    fn remove(&mut self, ptr: NonNull<CcBox<()>>) {
        self.size -= 1;
        self.list.remove(ptr)
    }
    #[inline]
    fn remove_first(&mut self) -> Option<NonNull<CcBox<()>>> {
        let ptr = self.list.remove_first();
        if ptr.is_some() {
            self.size -= 1;
        }
        ptr
    }
    #[inline]
    fn is_empty(&self) -> bool {
        self.size == 0
    }
    #[inline]
    #[cfg(any(feature = "pedantic-debug-assertions", all(test, feature = "std")))] fn contains(&self, ptr: NonNull<CcBox<()>>) -> bool {
        self.list.contains(ptr)
    }
    #[inline]
    fn iter(&self) -> Iter {
        self.list.iter()
    }
    #[inline]
    #[cfg(all(test, feature = "std"))] fn into_iter(self) -> ListIter<CountedList> {
        <Self as IntoIterator>::into_iter(self)
    }
}
impl<'a> IntoIterator for &'a CountedList {
    type Item = NonNull<CcBox<()>>;
    type IntoIter = Iter<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.list.iter()
    }
}
impl IntoIterator for CountedList {
    type Item = NonNull<CcBox<()>>;
    type IntoIter = ListIter<CountedList>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        ListIter {
            list: self,
        }
    }
}