use core::{
cell::Cell,
fmt::{Debug, Display},
};
use crate::Literator;
pub struct Literate<I> {
iter: Cell<Option<I>>,
}
impl<I: Sized> Literate<I> {
pub const fn new(iter: I) -> Self {
Self::new_cell(Some(iter))
}
pub const fn new_cell(iter: Option<I>) -> Self {
Literate {
iter: Cell::new(iter),
}
}
pub fn into_inner(self) -> Option<I> {
self.iter.take()
}
pub fn map_iterator<F, O>(self, f: F) -> Literate<O>
where
F: FnOnce(I) -> O,
{
if let Some(iter) = self.iter.into_inner() {
Literate::new(f(iter))
} else {
Literate {
iter: Cell::new(None),
}
}
}
pub(crate) fn map_literator<F, O>(self, f: F) -> Literate<O>
where
F: FnOnce(I) -> Literate<O>,
{
if let Some(iter) = self.iter.into_inner() {
f(iter)
} else {
Literate {
iter: Cell::new(None),
}
}
}
}
impl<I: Clone> Clone for Literate<I> {
fn clone(&self) -> Self {
if let Some(value) = self.iter.take() {
let cloned = value.clone();
self.iter.set(Some(value)); Literate::new(cloned)
} else {
Literate {
iter: Cell::new(None),
}
}
}
}
impl<I> Display for Literate<I>
where
I: Iterator<Item: Display>,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let Some(iter) = self.iter.take() else {
return Ok(());
};
for item in iter {
item.fmt(f)?;
}
Ok(())
}
}
impl<I> Debug for Literate<I>
where
I: Iterator<Item: Debug>,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let Some(iter) = self.iter.take() else {
return Ok(());
};
for item in iter {
item.fmt(f)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::format;
struct Foo;
impl Display for Foo {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("display")
}
}
impl Debug for Foo {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("debug")
}
}
#[test]
fn forward_display_debug() {
assert_eq!(
format!("{}", Literate::new([Foo, Foo].iter())),
"displaydisplay"
);
assert_eq!(
format!("{:?}", Literate::new([Foo, Foo].iter())),
"debugdebug"
);
}
}
impl<I> Literator for Literate<I>
where
I: Iterator + Sized,
{
type Item = I::Item;
type Iter = I;
fn into_option_iter(self) -> Option<Self::Iter> {
self.into_inner()
}
}