literator 0.2.0

Efficient conversion of iterators to human-readable strings
Documentation
//! Block adapters.

use core::{
    cell::Cell,
    fmt::{self, Display, Formatter},
};

use crate::{Literator, fmt::repeat};

/// Helper for [`Literator::inline_block()`].
pub struct InlineBlock<I, Open, Delim, Close> {
    iter: Cell<Option<I>>,
    open: Open,
    delim: Delim,
    close: Close,
}

impl<I, Open, Delim, Close> InlineBlock<I, Open, Delim, Close>
where
    I: Literator,
    Open: Display,
    Delim: Display,
    Close: Display,
{
    pub(super) fn new(iter: I, open: Open, delim: Delim, close: Close) -> Self {
        InlineBlock {
            iter: Cell::new(Some(iter)),
            open,
            delim,
            close,
        }
    }

    pub(crate) fn do_fmt<F>(&self, f: &mut Formatter, fmt_item: F) -> fmt::Result
    where
        F: Fn(&I::Item, &mut Formatter) -> fmt::Result,
    {
        let Self {
            iter,
            open,
            delim,
            close,
        } = self;

        let Some(mut iter) = iter.take() else {
            return Ok(());
        };

        write!(f, "{open}")?;
        if let Some(first) = iter.next() {
            f.write_str(" ")?;
            fmt_item(&first, f)?;
            for item in iter {
                write!(f, "{delim}")?;
                fmt_item(&item, f)?;
            }
            f.write_str(" ")?;
        }
        write!(f, "{close}")
    }
}

impl<I, Open, Delim, Close> Clone for InlineBlock<I, Open, Delim, Close>
where
    I: Copy,
    Open: Clone,
    Delim: Clone,
    Close: Clone,
{
    fn clone(&self) -> Self {
        Self {
            iter: self.iter.clone(),
            open: self.open.clone(),
            delim: self.delim.clone(),
            close: self.close.clone(),
        }
    }
}

/// Helper for [`Literator::indented_block()`].
pub struct IndentedBlock<I, Open, Close, Indentation, Newline> {
    iter: Cell<Option<I>>,
    open: Open,
    close: Close,
    indentation: Indentation,
    newline: Newline,
    inner_level: usize,
}

impl<I, Open, Close, Indentation, Newline> IndentedBlock<I, Open, Close, Indentation, Newline>
where
    I: Iterator,
    Open: Display,
    Close: Display,
    Indentation: Display,
    Newline: Display,
{
    pub(super) fn new(
        iter: I,
        open: Open,
        close: Close,
        indentation: Indentation,
        newline: Newline,
        inner_level: usize,
    ) -> Self {
        Self {
            iter: Cell::new(Some(iter)),
            open,
            close,
            indentation,
            newline,
            inner_level,
        }
    }

    pub(crate) fn do_fmt<F>(&self, f: &mut Formatter, fmt_item: F) -> fmt::Result
    where
        F: Fn(&I::Item, &mut Formatter) -> fmt::Result,
    {
        let Self {
            iter,
            open,
            close,
            indentation,
            newline,
            inner_level,
        } = self;

        let Some(mut iter) = iter.take() else {
            return Ok(());
        };

        write!(f, "{open}")?;
        if let Some(first) = iter.next() {
            let item_ident = repeat(indentation, *inner_level);

            write!(f, "{newline}{item_ident}")?;
            fmt_item(&first, f)?;
            write!(f, "{newline}")?;
            for item in iter {
                write!(f, "{item_ident}")?;
                fmt_item(&item, f)?;
                write!(f, "{newline}")?;
            }

            // Indentation of the closing delimiter.
            write!(f, "{}", repeat(indentation, (*inner_level).max(1) - 1))?;
        }
        write!(f, "{close}")
    }
}

impl<I, Open, Close, Indentation, Newline> Clone
    for IndentedBlock<I, Open, Close, Indentation, Newline>
where
    I: Copy,
    Open: Clone,
    Close: Clone,
    Indentation: Clone,
    Newline: Clone,
{
    fn clone(&self) -> Self {
        Self {
            iter: self.iter.clone(),
            open: self.open.clone(),
            close: self.close.clone(),
            indentation: self.indentation.clone(),
            newline: self.newline.clone(),
            inner_level: self.inner_level.clone(),
        }
    }
}