restd 0.3.0

A re-implementation of various std features
Documentation
//! Core implementation for formatting operations.
//!
//! The central traits are [`Format`], [`Style`], and [`Write`].
//!
//! Redesign of [`std::fmt`](https:?/doc.rust-lang.org/std/fmt/index.html).

mod adapters;
pub mod args;
mod binary;
mod debug;
mod derives;
mod display;
mod hex;
mod impls;
mod macros;
mod pad;
mod prefix;
mod pretty;

#[cfg(test)]
mod test;

#[cfg(any(feature = "alloc", test))]
use alloc::string::String;

pub use adapters::{RestdWrite, StdDebug, StdDisplay, StdWrite};
pub use binary::Binary;
pub use debug::Debug;
pub use derives::derive;
pub use display::Display;
pub use hex::Hex;
pub use pad::{Dir, Kind, Pad};
pub use prefix::Prefix;
pub use pretty::Pretty;

/// The type returned by formatter methods.
pub type Result = core::result::Result<(), Error>;

/// The error returned by formatter methods.
///
/// Should only ever be generated by [writers](Write).
///
/// Note that this carries no information: any extra info must be signaled
/// out-of-band, e.g. by a field on the writer.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Error;

/// A specific way to format things, e.g. [`Display`] or [`Hex`], for use by a
/// [`Format`].
///
/// Some styles (like `Display`) are merely markers; some, like [`Debug`](struct@Debug), have
/// methods on them to aid in using them; and some, like `Hex`, carry additional
/// information inside about how things should be formatted.
pub trait Style {}

/// A wrapper around a style, providing a modification to that style; for
/// example, [`Prefix`] merely prints something before something else.
pub trait Modifier: Style {
    /// The style wrapped by this modifier.
    type Inner: Style;

    /// Apply this modifier to any type.
    fn apply<T>(&self, f: &mut dyn Write, data: &T) -> Result
    where
        T: Format<Self::Inner> + ?Sized;
}

// TODO: can any form of this work?
// impl<T, M> Format<M> for T
// where
//     T: Format<M::Inner>,
//     M: Modifier,
// {
//     fn fmt(&self, f: &mut dyn Write, style: &M) -> Result {
//         style.apply(f, self)
//     }
// }

/// A type that can be formatted in a specific [style](Style).
///
/// All types implementing this should also use [`stylable`](crate::stylable).
///
/// A more general form of traits like `Display` and `Debug` in std; the
/// equivalent forms would be <code>Format<[Display]></code> and
/// <code>Format<[Debug](struct@Debug)></code>.
pub trait Format<S: Style> {
    /// Formats the value given a [writer](Write) and a [style](Style).
    fn fmt(&self, f: &mut dyn Write, style: &S) -> Result;

    /// Converts the value into a `String`.
    #[cfg(any(feature = "alloc", test))]
    fn stringify(&self, style: &S) -> String {
        let mut f = String::new();
        self.fmt(&mut f, style).unwrap();
        f
    }
}

/// A trait for writing or formatting into Unicode-accepting buffers or streams.
///
/// This trait only accepts UTF-8–encoded data and is not flushable. If you only
/// want to accept Unicode and you don’t need flushing, you should implement
/// this trait; otherwise you should implement [`io::Write`](crate::io::Write).
pub trait Write {
    /// Writes a string slice.
    ///
    /// This method can only succeed if the entire string slice was successfully
    /// written, and this method will not return until all data has been written
    /// or an error occurs.
    fn write_str(&mut self, data: &str) -> Result;

    /// Writes a single `char`
    ///
    /// A `char` can be multiple bytes. This method can only succeed if the
    /// entire byte sequence was successfully written, and this method will not
    /// return until all data has been written or an error occurs.
    fn write_char(&mut self, data: char) -> Result {
        self.write_str(data.encode_utf8(&mut [0; 4]))
    }

    /// Writes a sequence of [`Var`](args::Var)s. Should not be used or
    /// implemented directly.
    fn write_args(mut self: &mut Self, args: args::Arguments<'_>) -> Result
    where
        Self: Sized,
    {
        for var in args.0 {
            var.call(&mut self)?;
        }
        Ok(())
    }
}

impl<W: Write + ?Sized> Write for &mut W {
    fn write_str(&mut self, data: &str) -> Result {
        (*self).write_str(data)
    }

    fn write_char(&mut self, data: char) -> Result {
        (*self).write_char(data)
    }
}

/// Use this on any and all types implementing any kind of `Format`. This allows
/// a given type to be styled with any modifier.
///
/// Can either be used as `stylable!(Type)`, or
/// `stylable!(for('a, T) Type<'a, T>)` (no trailing commas!).
///
/// Automatically applied with [`derive`].
#[macro_export]
macro_rules! stylable {
    (for($($gen:tt)*) $($typ:tt)*) => {
        impl<
            $($gen)*,
            __StylableModifier,
        > $crate::fmt::Format<__StylableModifier> for $($typ)*
        where
            $($typ)*: $crate::fmt::Format<__StylableModifier::Inner>,
            __StylableModifier: $crate::fmt::Modifier,
        {
            fn fmt(
                &self,
                f: &mut dyn $crate::fmt::Write,
                style: &__StylableModifier,
            ) -> $crate::fmt::Result {
                style.apply(f, self)
            }
        }
    };

    ($($typ:ty),+ $(,)?) => {$(
        impl<M> $crate::fmt::Format<M> for $typ
        where
            $typ: $crate::fmt::Format<M::Inner>,
            M: $crate::fmt::Modifier,
        {
            fn fmt(&self, f: &mut dyn $crate::fmt::Write, style: &M) -> $crate::fmt::Result {
                style.apply(f, self)
            }
        }
    )+};
}

#[doc(hidden)]
#[cfg(any(feature = "std", test))]
pub fn _print(args: args::Arguments<'_>) {
    crate::io::IoFmt::new(std::io::stdout())
        .write_args(args)
        .unwrap();
}

#[doc(hidden)]
#[cfg(any(feature = "std", test))]
pub fn _eprint(args: args::Arguments<'_>) {
    crate::io::IoFmt::new(std::io::stderr())
        .write_args(args)
        .unwrap();
}

#[doc(hidden)]
#[cfg(any(feature = "alloc", test))]
pub fn _format(args: args::Arguments<'_>) -> String {
    let mut s = String::new();
    args.write(&mut s).unwrap();
    s
}