use generic_array::typenum as t;
use time::{PrimitiveDateTime, UtcOffset};
use crate::ts_str::{template, FormatString, IsValidFormat, TimestampStr};
#[rustfmt::skip]
#[allow(unused_assignments, clippy::identity_op)]
#[inline(always)]
pub fn do_format<F: t::Bit, O: t::Bit, P: t::Unsigned>(ts: PrimitiveDateTime, offset: UtcOffset) -> TimestampStr<FormatString<F, O, P>>
where
FormatString<F, O, P>: IsValidFormat,
{
let (mut year, month, day) = crate::impls::to_calendar_date(ts.date());
let (hour, minute, second, nanoseconds) = ts.as_hms_nano();
let mut template = template::<F, O, P>();
let buf = template.as_mut();
if unlikely!(year < 0) {
year = -year; buf[0] = b'-';
}
let mut pos = 1;
macro_rules! write_num {
($s: expr, $len: expr, $max: expr) => {{
let mut value = $s;
let mut len = $len;
let mut d1 = 0;
unsafe { assume!(value <= $max); }
let buf = &mut buf[pos..];
pos += $len;
if F::BOOL { pos += 1; }
while len >= 2 {
(value, d1) = (value / 100, value % 100);
let (a, b) = (d1 / 10, d1 % 10);
len -= 1; buf[len] = (b as u8) | b'0';
len -= 1; buf[len] = (a as u8) | b'0';
}
if len == 1 {
buf[0] = (value as u8) | b'0';
}
}};
}
write_num!(year as u16, 4, 9999); write_num!(month as u8, 2, 12); write_num!(day, 2, 31); if !F::BOOL { pos += 1; } write_num!(hour, 2, 59); write_num!(minute, 2, 59); write_num!(second, 2, 59); if !F::BOOL && P::USIZE > 0 { pos += 1; }
match P::USIZE {
1 => write_num!(nanoseconds / 100000000, 1, 9), 2 => write_num!(nanoseconds / 10000000, 2, 99), 3 => write_num!(nanoseconds / 1000000, 3, 999), 4 => write_num!(nanoseconds / 100000, 4, 9999), 5 => write_num!(nanoseconds / 10000, 5, 99999), 6 => write_num!(nanoseconds / 1000, 6, 999999), 7 => write_num!(nanoseconds / 100, 7, 9999999), 8 => write_num!(nanoseconds / 10, 8, 99999999), 9 => write_num!(nanoseconds / 1, 9, 999999999), _ => {}
}
if O::BOOL {
if !F::BOOL { pos += 1; }
if offset.is_negative() {
buf[pos - 1] = b'-';
}
let (h, m, _) = offset.as_hms();
write_num!(h.abs(), 2, 23); if !F::BOOL { pos += 1; } write_num!(m.abs(), 2, 59); }
TimestampStr(template)
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "std")]
#[test]
fn test_template() {
let now = crate::Timestamp::now_utc();
fn as_str(x: &[u8]) -> &str {
core::str::from_utf8(x).unwrap()
}
macro_rules! g {
($($f:ty, $o:ty, $p:ty;)*) => {$(
println!("{} -> {}",
as_str(&template::<$f, $o, $p>()),
now.format_raw::<$f, $o, $p>(time::UtcOffset::from_hms(-6, 0, 0).unwrap())
);
)*}
}
g! {
t::True, t::True, t::U0;
t::True, t::True, t::U1;
t::True, t::True, t::U2;
t::True, t::True, t::U3;
t::True, t::True, t::U4;
t::True, t::True, t::U5;
t::True, t::True, t::U6;
t::True, t::True, t::U7;
t::True, t::True, t::U8;
t::True, t::True, t::U9;
t::True, t::False, t::U0;
t::True, t::False, t::U1;
t::True, t::False, t::U2;
t::True, t::False, t::U3;
t::True, t::False, t::U4;
t::True, t::False, t::U5;
t::True, t::False, t::U6;
t::True, t::False, t::U7;
t::True, t::False, t::U8;
t::True, t::False, t::U9;
t::False, t::True, t::U0;
t::False, t::True, t::U1;
t::False, t::True, t::U2;
t::False, t::True, t::U3;
t::False, t::True, t::U4;
t::False, t::True, t::U5;
t::False, t::True, t::U6;
t::False, t::True, t::U7;
t::False, t::True, t::U8;
t::False, t::True, t::U9;
t::False, t::False, t::U0;
t::False, t::False, t::U1;
t::False, t::False, t::U2;
t::False, t::False, t::U3;
t::False, t::False, t::U4;
t::False, t::False, t::U5;
t::False, t::False, t::U6;
t::False, t::False, t::U7;
t::False, t::False, t::U8;
t::False, t::False, t::U9;
}
}
}