macro_rules! pad {
($f:ident, $padding:ident(None), $width:literal, $value:expr) => {
match $padding {
Padding::None | Padding::Default => write!($f, "{}", $value),
Padding::Space => write!($f, concat!("{:", stringify!($width), "}"), $value),
Padding::Zero => write!($f, concat!("{:0", stringify!($width), "}"), $value),
}
};
($f:ident, $padding:ident(Space), $width:literal, $value:expr) => {
match $padding {
Padding::None => write!($f, "{}", $value),
Padding::Space | Padding::Default => {
write!($f, concat!("{:", stringify!($width), "}"), $value)
}
Padding::Zero => write!($f, concat!("{:0", stringify!($width), "}"), $value),
}
};
($f:ident, $padding:ident(Zero), $width:literal, $value:expr) => {
match $padding {
Padding::None => write!($f, "{}", $value),
Padding::Space => write!($f, concat!("{:", stringify!($width), "}"), $value),
Padding::Zero | Padding::Default => {
write!($f, concat!("{:0", stringify!($width), "}"), $value)
}
}
};
}
pub(crate) mod date;
pub(crate) mod offset;
pub(crate) mod parse;
pub(crate) mod parse_items;
pub(crate) mod time;
#[cfg(not(feature = "std"))]
use crate::no_std_prelude::*;
use crate::{Date, Time, UtcOffset};
use core::fmt::{self, Display, Formatter};
#[allow(unreachable_pub)]
#[allow(unreachable_pub)]
pub use parse::ParseError;
pub(crate) use parse::{parse, ParseResult, ParsedItems};
pub(crate) use parse_items::{parse_fmt_string, try_parse_fmt_string};
#[inline(always)]
pub fn validate_format_string(s: &str) -> Result<(), String> {
try_parse_fmt_string(s).map(|_| ())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum Padding {
None,
Space,
Zero,
Default,
}
impl Padding {
#[inline(always)]
pub(crate) fn default_to(self, value: Self) -> Self {
match self {
Self::Default => value,
_ => self,
}
}
}
#[allow(
non_snake_case,
non_camel_case_types,
clippy::missing_docs_in_private_items
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum Specifier {
a,
A,
b,
B,
c,
C { padding: Padding },
d { padding: Padding },
D,
F,
g { padding: Padding },
G { padding: Padding },
H { padding: Padding },
I { padding: Padding },
j { padding: Padding },
m { padding: Padding },
M { padding: Padding },
p,
P,
r,
R,
S { padding: Padding },
T,
u,
U { padding: Padding },
V { padding: Padding },
w,
W { padding: Padding },
y { padding: Padding },
Y { padding: Padding },
z,
}
#[inline]
fn format_specifier(
f: &mut Formatter<'_>,
date: Option<Date>,
time: Option<Time>,
offset: Option<UtcOffset>,
specifier: Specifier,
) -> fmt::Result {
macro_rules! specifier {
($type:ident :: $specifier_fn:ident ( $specifier:ident $(, $param:expr)? )) => {
$type::$specifier_fn(
f,
$type.expect(concat!(
"Specifier `%",
stringify!($specifier),
"` requires a ",
stringify!($type),
" to be present."
)),
$($param)?
)?
};
}
macro_rules! literal {
($string:literal) => {
f.write_str($string)?
};
}
use Specifier::*;
match specifier {
a => specifier!(date::fmt_a(a)),
A => specifier!(date::fmt_A(A)),
b => specifier!(date::fmt_b(b)),
B => specifier!(date::fmt_B(B)),
c => {
specifier!(date::fmt_a(a));
literal!(" ");
specifier!(date::fmt_b(b));
literal!(" ");
specifier!(date::fmt_d(d, Padding::None));
literal!(" ");
specifier!(time::fmt_H(H, Padding::None));
literal!(":");
specifier!(time::fmt_M(M, Padding::Default));
literal!(":");
specifier!(time::fmt_S(S, Padding::Default));
literal!(" ");
specifier!(date::fmt_Y(Y, Padding::None));
}
C { padding } => specifier!(date::fmt_C(C, padding)),
d { padding } => specifier!(date::fmt_d(d, padding)),
D => {
specifier!(date::fmt_m(m, Padding::None));
literal!("/");
specifier!(date::fmt_d(d, Padding::Default));
literal!("/");
specifier!(date::fmt_y(y, Padding::Default));
}
F => {
specifier!(date::fmt_Y(Y, Padding::None));
literal!("-");
specifier!(date::fmt_m(m, Padding::Default));
literal!("-");
specifier!(date::fmt_d(d, Padding::Default));
}
g { padding } => specifier!(date::fmt_g(g, padding)),
G { padding } => specifier!(date::fmt_G(G, padding)),
H { padding } => specifier!(time::fmt_H(H, padding)),
I { padding } => specifier!(time::fmt_I(I, padding)),
j { padding } => specifier!(date::fmt_j(j, padding)),
m { padding } => specifier!(date::fmt_m(m, padding)),
M { padding } => specifier!(time::fmt_M(M, padding)),
p => specifier!(time::fmt_p(p)),
P => specifier!(time::fmt_P(P)),
r => {
specifier!(time::fmt_I(I, Padding::None));
literal!(":");
specifier!(time::fmt_M(M, Padding::Default));
literal!(":");
specifier!(time::fmt_S(S, Padding::Default));
literal!(" ");
specifier!(time::fmt_p(p));
}
R => {
specifier!(time::fmt_H(H, Padding::None));
literal!(":");
specifier!(time::fmt_M(M, Padding::Default));
}
S { padding } => specifier!(time::fmt_S(S, padding)),
T => {
specifier!(time::fmt_H(H, Padding::None));
literal!(":");
specifier!(time::fmt_M(M, Padding::Default));
literal!(":");
specifier!(time::fmt_S(S, Padding::Default));
}
u => specifier!(date::fmt_u(u)),
U { padding } => specifier!(date::fmt_U(U, padding)),
V { padding } => specifier!(date::fmt_V(V, padding)),
w => specifier!(date::fmt_w(w)),
W { padding } => specifier!(date::fmt_W(W, padding)),
y { padding } => specifier!(date::fmt_y(y, padding)),
Y { padding } => specifier!(date::fmt_Y(Y, padding)),
z => specifier!(offset::fmt_z(z)),
}
Ok(())
}
#[allow(variant_size_differences, single_use_lifetimes)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) enum FormatItem<'a> {
Literal(&'a str),
Specifier(Specifier),
}
#[allow(single_use_lifetimes)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) struct DeferredFormat<'a> {
pub(crate) date: Option<Date>,
pub(crate) time: Option<Time>,
pub(crate) offset: Option<UtcOffset>,
pub(crate) format: Vec<FormatItem<'a>>,
}
impl Display for DeferredFormat<'_> {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for item in &self.format {
match item {
FormatItem::Literal(value) => f.write_str(value)?,
FormatItem::Specifier(specifier) => {
format_specifier(f, self.date, self.time, self.offset, *specifier)?
}
}
}
Ok(())
}
}