parse-display-with 0.0.2

Custom formatting/parsing utilities for parse-display.
Documentation
use core::{
    fmt::{self, Display, Formatter},
    marker::PhantomData,
    result::Result,
    str::FromStr,
};

use parse_display::{DisplayFormat, FromStrFormat};

pub struct Fmt;

impl<T: ?Sized + Display> DisplayFormat<T> for Fmt {
    fn write(&self, f: &mut Formatter, value: &T) -> fmt::Result {
        write!(f, "{value}")
    }
}
impl<T: FromStr> FromStrFormat<T> for Fmt {
    type Err = T::Err;
    fn parse(&self, s: &str) -> Result<T, Self::Err> {
        s.parse()
    }
}

pub fn fmt() -> Fmt {
    Fmt
}

pub fn fmt_display<T: ?Sized>(
    f: impl Fn(&mut Formatter, &T) -> fmt::Result,
) -> impl DisplayFormat<T> {
    struct FnFmtDisplay<F>(F);
    impl<T, F> DisplayFormat<T> for FnFmtDisplay<F>
    where
        T: ?Sized,
        F: Fn(&mut Formatter, &T) -> fmt::Result,
    {
        fn write(&self, f: &mut Formatter, t: &T) -> fmt::Result {
            (self.0)(f, t)
        }
    }
    FnFmtDisplay(f)
}

pub fn fmt_from_str<T, E>(f: impl Fn(&str) -> Result<T, E>) -> impl FromStrFormat<T, Err = E> {
    struct FnFmtFromStr<F>(F);
    impl<T, E, F> FromStrFormat<T> for FnFmtFromStr<F>
    where
        F: Fn(&str) -> Result<T, E>,
    {
        type Err = E;
        fn parse(&self, s: &str) -> Result<T, E> {
            (self.0)(s)
        }
    }
    FnFmtFromStr(f)
}

pub struct Join<'a, I: ?Sized, F = Fmt> {
    item_format: F,
    delimiter: &'a str,
    _phantom: PhantomData<I>,
}

impl<T, I, F> DisplayFormat<T> for Join<'_, I, F>
where
    T: ?Sized,
    for<'a> &'a T: IntoIterator<Item = &'a I>,
    F: DisplayFormat<I>,
{
    fn write(&self, f: &mut Formatter, value: &T) -> fmt::Result {
        let mut iter = value.into_iter();
        if let Some(first) = iter.next() {
            self.item_format.write(f, first)?;
            for item in iter {
                write!(f, "{}", self.delimiter)?;
                self.item_format.write(f, item)?;
            }
        }
        Ok(())
    }
}
impl<T, I, F> FromStrFormat<T> for Join<'_, I, F>
where
    F: FromStrFormat<I>,
    T: FromIterator<I>,
{
    type Err = F::Err;
    fn parse(&self, s: &str) -> Result<T, Self::Err> {
        s.split(self.delimiter)
            .map(|item| self.item_format.parse(item))
            .collect()
    }
}

pub fn join<I: ?Sized, F>(item_format: F, delimiter: &str) -> Join<I, F> {
    Join {
        item_format,
        delimiter,
        _phantom: PhantomData,
    }
}

pub fn delimiter<I: ?Sized>(delimiter: &str) -> Join<I> {
    join(fmt(), delimiter)
}