dfmt 0.4.1

A fully featured dynamic template drop in replacement for the format! macro.
Documentation
use core::fmt::{Binary, Debug, Display, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex};

use crate::values::Type;

/// Possible variants of an argument.
pub enum ArgumentValue<'ct> {
    Display(&'ct dyn Display),
    Debug(&'ct dyn Debug),
    Binary(&'ct dyn Binary),
    LowerExp(&'ct dyn LowerExp),
    UpperExp(&'ct dyn UpperExp),
    LowerHex(&'ct dyn LowerHex),
    UpperHex(&'ct dyn UpperHex),
    Octal(&'ct dyn Octal),
    Pointer(&'ct dyn Pointer),
    WidthOrPrecisionAmount(&'ct dyn WidthOrPrecisionAmount),
}

impl<'ct> ArgumentValue<'ct> {
    pub fn to_u16(&self) -> Option<u16> {
        match self {
            ArgumentValue::WidthOrPrecisionAmount(value) => Some(value.to_u16()),
            _ => None,
        }
    }

    pub fn to_type(&self) -> Type {
        match self {
            ArgumentValue::Display(_) => Type::Display,
            ArgumentValue::Debug(_) => Type::Debug,
            ArgumentValue::Binary(_) => Type::Binary,
            ArgumentValue::LowerExp(_) => Type::LowerExp,
            ArgumentValue::UpperExp(_) => Type::UpperExp,
            ArgumentValue::LowerHex(_) => Type::LowerHex,
            ArgumentValue::UpperHex(_) => Type::UpperHex,
            ArgumentValue::Octal(_) => Type::Octal,
            ArgumentValue::Pointer(_) => Type::Pointer,
            ArgumentValue::WidthOrPrecisionAmount(_) => Type::WidthOrPrecisionAmount,
        }
    }
}

impl<'ct> core::fmt::Display for ArgumentValue<'ct> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            ArgumentValue::Display(display) => (*display).fmt(f),
            ArgumentValue::Debug(debug) => (*debug).fmt(f),
            ArgumentValue::Binary(binary) => (*binary).fmt(f),
            ArgumentValue::LowerExp(lower_exp) => (*lower_exp).fmt(f),
            ArgumentValue::UpperExp(upper_exp) => (*upper_exp).fmt(f),
            ArgumentValue::LowerHex(lower_hex) => (*lower_hex).fmt(f),
            ArgumentValue::UpperHex(upper_hex) => (*upper_hex).fmt(f),
            ArgumentValue::Octal(octal) => (*octal).fmt(f),
            ArgumentValue::Pointer(pointer) => (*pointer).fmt(f),
            ArgumentValue::WidthOrPrecisionAmount(_) => {
                unreachable!()
            }
        }
    }
}

#[doc(hidden)]
pub trait WidthOrPrecisionAmount {
    fn to_u16(&self) -> u16;
}

macro_rules! impl_width_or_precision_amount {
    (true, $ty:ty) => {
        impl WidthOrPrecisionAmount for $ty {
            fn to_u16(&self) -> u16 {
                *self as u16
            }
        }
    };
    (false, $ty:ty) => {
        impl WidthOrPrecisionAmount for $ty {
            fn to_u16(&self) -> u16 {
                if *self < 0 {
                    0
                } else {
                    *self as u16
                }
            }
        }
    };
}

impl_width_or_precision_amount!(false, i8);
impl_width_or_precision_amount!(true, u8);
impl_width_or_precision_amount!(false, i16);
impl_width_or_precision_amount!(true, u16);
impl_width_or_precision_amount!(false, i32);
impl_width_or_precision_amount!(true, u32);
impl_width_or_precision_amount!(false, i64);
impl_width_or_precision_amount!(true, u64);
impl_width_or_precision_amount!(false, i128);
impl_width_or_precision_amount!(true, u128);