literator 0.2.0

Efficient conversion of iterators to human-readable strings
Documentation
//! General formatting utilities.

use core::fmt::{Debug, Display, Formatter, Result, Write};

/// Polyfill for the unstable
/// [`std::fmt::from_fn()`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html).
pub fn from_fn<F>(f: F) -> FromFn<F> {
    FromFn(f)
}

/// Helper for [`from_fn()`].
pub struct FromFn<F>(F);

impl<F> Display for FromFn<F>
where
    F: Fn(&mut Formatter) -> Result,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        (self.0)(f)
    }
}

impl<F> Debug for FromFn<F>
where
    F: Fn(&mut Formatter) -> Result,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        (self.0)(f)
    }
}

/// Adapter whose `Display` implementation displays `T` repeated `n` times.
///
/// This can be used to programmatically create indentation and spacing.
///
/// # Example
///
/// ```
/// # use literator::fmt::repeat;
/// assert_eq!(repeat('æ', 5).to_string(), "æææææ");
/// ```
pub fn repeat<T>(item: T, n: usize) -> Repeat<T> {
    Repeat { item, n }
}

/// Helper for [`repeat()`].
#[derive(Clone, Copy)]
pub struct Repeat<T> {
    /// The item to repeat.
    pub item: T,
    /// The number of times to display `item`.
    pub n: usize,
}

impl<T: Display> Display for Repeat<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        for _ in 0..self.n {
            self.item.fmt(f)?;
        }
        Ok(())
    }
}

/// Wrapper type whose `Display` and `Debug` implementations call `F`.
pub struct FormatWith<T, F> {
    /// The item to pass to `F`.
    pub item: T,
    /// The function to call.
    pub with: F,
}

impl<T, F> Display for FormatWith<T, F>
where
    F: Fn(&T, &mut Formatter) -> Result,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        (self.with)(&self.item, f)
    }
}

impl<T, F> Debug for FormatWith<T, F>
where
    F: Fn(&T, &mut Formatter) -> Result,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        (self.with)(&self.item, f)
    }
}

/// Display `T` in uppercase using [`char::to_uppercase()`]. Unicode compatible.
///
/// Due to current limitations in the standard library, this only works with
/// `Display`, not other formatting traits.
///
/// # Example
///
/// ```
/// # use literator::fmt::*;
/// assert_eq!(Uppercase("abc").to_string(), "ABC");
/// assert_eq!(Uppercase("äöå").to_string(), "ÄÖÅ");
/// ```
pub struct Uppercase<T>(pub T);

/// Display `T` in uppercase using [`char::to_lowercase()`]. Unicode compatible.
///
/// Due to current limitations in the standard library, this only works with
/// `Display`, not other formatting traits.
///
/// # Example
///
/// ```
/// # use literator::fmt::*;
/// assert_eq!(Lowercase("ABC").to_string(), "abc");
/// assert_eq!(Lowercase("ÄÖÅ").to_string(), "äöå");
/// ```
pub struct Lowercase<T>(pub T);

/// Display `T`, converting the first printed character to uppercase using
/// [`char::to_uppercase()`]. Unicode compatible.
///
/// Due to current limitations in the standard library, this only works with
/// `Display`, not other formatting traits.
///
/// # Example
///
/// ```
/// # use literator::{fmt::*, Literator};
/// assert_eq!(Capitalize("hello").to_string(), "Hello");
/// assert_eq!(Capitalize("δεκαήμερο").to_string(), "Δεκαήμερο");
/// assert_eq!(Capitalize("æblegrød").to_string(), "Æblegrød");
///
/// assert_eq!(
///     ["hello", "δεκαήμερο", "æblegrød"]
///         .iter()
///         .map(Capitalize)
///         .join(", ")
///         .to_string(),
///     "Hello, Δεκαήμερο, Æblegrød",
/// );
/// ```
pub struct Capitalize<T>(pub T);

impl<T: Display> Display for Uppercase<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        struct UppercaseWriter<'a, 'b>(&'a mut Formatter<'b>);
        impl<'a, 'b> Write for UppercaseWriter<'a, 'b> {
            fn write_str(&mut self, s: &str) -> Result {
                // TODO: This can be optimized by specializing ranges of ASCII.
                for ch in s.chars() {
                    write!(self.0, "{}", ch.to_uppercase())?;
                }
                Ok(())
            }

            #[inline]
            fn write_char(&mut self, c: char) -> Result {
                write!(self.0, "{}", c.to_uppercase())
            }
        }

        write!(&mut UppercaseWriter(f), "{}", self.0)
    }
}

impl<T: Display> Display for Lowercase<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        struct LowercaseWriter<'a, 'b>(&'a mut Formatter<'b>);
        impl<'a, 'b> Write for LowercaseWriter<'a, 'b> {
            fn write_str(&mut self, s: &str) -> Result {
                // TODO: This can be optimized by specializing ranges of ASCII.
                for ch in s.chars() {
                    write!(self.0, "{}", ch.to_lowercase())?;
                }
                Ok(())
            }

            #[inline]
            fn write_char(&mut self, c: char) -> Result {
                write!(self.0, "{}", c.to_lowercase())
            }
        }

        write!(&mut LowercaseWriter(f), "{}", self.0)
    }
}

impl<T: Display> Display for Capitalize<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        struct CapitalizeWriter<'a, 'b>(&'a mut Formatter<'b>, bool);
        impl<'a, 'b> Write for CapitalizeWriter<'a, 'b> {
            fn write_str(&mut self, s: &str) -> Result {
                if !self.1 {
                    let mut chars = s.chars();
                    if let Some(first) = chars.next() {
                        self.1 = true;
                        write!(self.0, "{}", first.to_uppercase())?;
                        self.0.write_str(chars.as_str())
                    } else {
                        Ok(())
                    }
                } else {
                    self.0.write_str(s)
                }
            }

            #[inline]
            fn write_char(&mut self, c: char) -> Result {
                if !self.1 {
                    self.1 = true;
                    write!(self.0, "{}", c.to_uppercase())
                } else {
                    write!(self.0, "{c}")
                }
            }
        }

        write!(&mut CapitalizeWriter(f, false), "{}", self.0)
    }
}

/// Utility type with an empty `Display` implementation (no output).
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Empty;

impl Display for Empty {
    #[inline(always)]
    fn fmt(&self, _: &mut Formatter<'_>) -> Result {
        Ok(())
    }
}