use std::{fmt, iter::FusedIterator, mem::MaybeUninit, ops::Drop, ptr::NonNull};
#[repr(transparent)]
pub struct MaybeEmpty<T>(MaybeUninit<T>)
where
T: IsEmpty;
pub unsafe trait IsEmpty: Sized {
fn is_empty(value: &MaybeEmpty<Self>) -> bool;
}
impl<T> MaybeEmpty<T>
where
T: IsEmpty,
{
pub fn new(value: T) -> MaybeEmpty<T> {
MaybeEmpty(MaybeUninit::new(value))
}
pub fn is_empty(&self) -> bool {
IsEmpty::is_empty(self)
}
pub fn as_non_null(&self) -> NonNull<T> {
NonNull::from_ref(self).cast::<T>()
}
pub fn as_option(&self) -> Option<&T> {
if self.is_empty() {
None
} else {
Some(unsafe { self.as_non_null().as_ref() })
}
}
pub fn as_option_mut(&mut self) -> Option<&mut T> {
if self.is_empty() {
None
} else {
Some(unsafe { self.as_non_null().as_mut() })
}
}
}
impl<T> fmt::Debug for MaybeEmpty<T>
where
T: IsEmpty + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(value) = self.as_option() {
value.fmt(f)
} else {
write!(f, "<empty>")
}
}
}
impl<T> From<T> for MaybeEmpty<T>
where
T: IsEmpty,
{
fn from(value: T) -> MaybeEmpty<T> {
MaybeEmpty(MaybeUninit::new(value))
}
}
impl<T> Drop for MaybeEmpty<T>
where
T: IsEmpty,
{
fn drop(&mut self) {
if self.is_empty() {
unsafe { self.0.assume_init_drop() };
}
}
}
pub struct NonEmptyIter<'a, E, I>(I)
where
E: IsEmpty + 'a,
I: Iterator<Item = &'a MaybeEmpty<E>>;
impl<'a, E, I> Iterator for NonEmptyIter<'a, E, I>
where
E: IsEmpty + 'a,
I: Iterator<Item = &'a MaybeEmpty<E>>,
{
type Item = &'a E;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
Some(entry) => {
if let Some(entry) = entry.as_option() {
return Some(entry);
}
}
None => return None,
}
}
}
}
impl<'a, E, I> FusedIterator for NonEmptyIter<'a, E, I>
where
E: IsEmpty + 'a,
I: Iterator<Item = &'a MaybeEmpty<E>> + FusedIterator,
{
}
pub trait NonEmptyIteratorExt<'a, E>: Iterator<Item = &'a MaybeEmpty<E>>
where
E: IsEmpty + 'a,
Self: Sized,
{
fn non_empty(self) -> NonEmptyIter<'a, E, Self>;
}
impl<'a, E, I> NonEmptyIteratorExt<'a, E> for I
where
E: IsEmpty + 'a,
I: Iterator<Item = &'a MaybeEmpty<E>> + Sized,
{
fn non_empty(self) -> NonEmptyIter<'a, E, Self> {
NonEmptyIter(self)
}
}
pub struct NonEmptyIterMut<'a, E, I>(I)
where
E: IsEmpty + 'a,
I: Iterator<Item = &'a mut MaybeEmpty<E>>;
impl<'a, E, I> Iterator for NonEmptyIterMut<'a, E, I>
where
E: IsEmpty + 'a,
I: Iterator<Item = &'a mut MaybeEmpty<E>>,
{
type Item = &'a mut E;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
Some(entry) => {
if let Some(entry) = entry.as_option_mut() {
return Some(entry);
}
}
None => return None,
}
}
}
}
pub trait NonEmptyIteratorMutExt<'a, E>: Iterator<Item = &'a mut MaybeEmpty<E>>
where
E: IsEmpty + 'a,
Self: Sized,
{
fn non_empty(self) -> NonEmptyIterMut<'a, E, Self>;
}
impl<'a, E, I> NonEmptyIteratorMutExt<'a, E> for I
where
E: IsEmpty + 'a,
I: Iterator<Item = &'a mut MaybeEmpty<E>> + Sized,
{
fn non_empty(self) -> NonEmptyIterMut<'a, E, Self> {
NonEmptyIterMut(self)
}
}