use core::{sync::atomic::Ordering, time::Duration};
use crate::RtVdsoVtable;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct Instant {
ticks: u64, }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct SystemTime {
nanos: u128, }
#[allow(unused)]
pub const UNIX_EPOCH: SystemTime = SystemTime { nanos: 0u128 };
const NANOS_IN_SEC: u64 = 1_000_000_000;
impl Instant {
pub const fn nan() -> Self {
Instant { ticks: 0 }
}
pub fn is_nan(&self) -> bool {
self.ticks == 0
}
pub fn from_u64(val: u64) -> Self {
Instant { ticks: val }
}
pub fn as_u64(&self) -> u64 {
self.ticks
}
pub fn now() -> Self {
let vdso_time_instant_now: extern "C" fn() -> u64 = unsafe {
core::mem::transmute(
RtVdsoVtable::get().time_instant_now.load(Ordering::Relaxed) as usize as *const ()
)
};
Self {
ticks: vdso_time_instant_now(),
}
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
if earlier.ticks > self.ticks {
return Duration::ZERO;
}
let ticks_diff = self.ticks - earlier.ticks;
if ticks_diff == 0 {
return Duration::ZERO;
}
let nanos = ticks_to_nanos(ticks_diff);
Duration::new(
(nanos / (NANOS_IN_SEC as u128)) as u64,
(nanos % (NANOS_IN_SEC as u128)) as u32,
)
}
pub fn elapsed(&self) -> Duration {
Instant::now().duration_since(*self)
}
pub const fn infinite_future() -> Self {
Instant { ticks: u64::MAX }
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
if *self < *other {
return None;
}
let result_ticks = self.ticks - other.ticks;
let result_nanos = ticks_to_nanos(result_ticks);
if result_nanos > (u64::MAX as u128) {
None
} else {
Some(Duration::from_nanos(result_nanos as u64))
}
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
let tsc_secs = other.as_secs().checked_mul(ticks_in_sec())?;
let tsc_diff = nanos_to_ticks(other.subsec_nanos() as u64).checked_add(tsc_secs)?;
Some(Instant {
ticks: self.ticks.checked_add(tsc_diff)?,
})
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
let tsc_secs = other.as_secs().checked_mul(ticks_in_sec())?;
let tsc_diff = nanos_to_ticks(other.subsec_nanos() as u64).checked_add(tsc_secs)?;
if tsc_diff > self.ticks {
None
} else {
Some(Instant {
ticks: self.ticks - tsc_diff,
})
}
}
}
impl core::ops::Add<Duration> for Instant {
type Output = Instant;
fn add(self, other: Duration) -> Instant {
let tsc_secs = other.as_secs() * ticks_in_sec();
let tsc_diff = nanos_to_ticks(other.subsec_nanos() as u64) + tsc_secs;
Instant {
ticks: self.ticks + tsc_diff,
}
}
}
impl core::ops::Sub<Duration> for Instant {
type Output = Instant;
fn sub(self, other: Duration) -> Self::Output {
let tsc_secs = other.as_secs() * ticks_in_sec();
let tsc_diff = nanos_to_ticks(other.subsec_nanos() as u64) + tsc_secs;
Instant {
ticks: self.ticks - tsc_diff,
}
}
}
pub fn since_system_start() -> Duration {
Instant::now()
.checked_sub_instant(&Instant { ticks: 0 })
.unwrap()
}
impl SystemTime {
pub fn now() -> Self {
SystemTime {
nanos: abs_ticks_to_nanos(Instant::now().ticks),
}
}
pub fn as_u128(&self) -> u128 {
self.nanos
}
pub fn from_u128(val: u128) -> Self {
Self { nanos: val }
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
if self.nanos >= other.nanos {
let total_nanos = self.nanos - other.nanos;
let secs = total_nanos / (NANOS_IN_SEC as u128);
let nanos = total_nanos % (NANOS_IN_SEC as u128);
Ok(Duration::new(secs as u64, nanos as u32))
} else {
let total_nanos = other.nanos - self.nanos;
let secs = total_nanos / (NANOS_IN_SEC as u128);
let nanos = total_nanos % (NANOS_IN_SEC as u128);
Err(Duration::new(secs as u64, nanos as u32))
}
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
self.nanos
.checked_add(other.as_nanos())
.map(|nanos| Self { nanos })
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
self.nanos
.checked_sub(other.as_nanos())
.map(|nanos| Self { nanos })
}
}
fn ticks_to_nanos(ticks: u64) -> u128 {
let vdso_ticks_to_nanos: extern "C" fn(u64, *mut u64, *mut u64) = unsafe {
core::mem::transmute(
RtVdsoVtable::get()
.time_ticks_to_nanos
.load(Ordering::Relaxed) as usize as *const (),
)
};
let mut hi = 0_u64;
let mut lo = 0_u64;
vdso_ticks_to_nanos(ticks, &mut hi, &mut lo);
((hi as u128) << 64) + (lo as u128)
}
fn abs_ticks_to_nanos(ticks: u64) -> u128 {
let vdso_abs_ticks_to_nanos: extern "C" fn(u64, *mut u64, *mut u64) = unsafe {
core::mem::transmute(
RtVdsoVtable::get()
.time_abs_ticks_to_nanos
.load(Ordering::Relaxed) as usize as *const (),
)
};
let mut hi = 0_u64;
let mut lo = 0_u64;
vdso_abs_ticks_to_nanos(ticks, &mut hi, &mut lo);
((hi as u128) << 64) + (lo as u128)
}
fn nanos_to_ticks(nanos: u64) -> u64 {
let vdso_nanos_to_ticks: extern "C" fn(u64) -> u64 = unsafe {
core::mem::transmute(
RtVdsoVtable::get()
.time_nanos_to_ticks
.load(Ordering::Relaxed) as usize as *const (),
)
};
vdso_nanos_to_ticks(nanos)
}
fn ticks_in_sec() -> u64 {
RtVdsoVtable::get()
.time_ticks_in_sec
.load(Ordering::Relaxed)
}
#[derive(Debug)]
pub struct UtcDateTime {
pub year: u32,
pub month: u8, pub day: u8, pub hour: u8,
pub minute: u8,
pub second: u8,
pub nanosecond: u32,
}
impl core::fmt::Display for UtcDateTime {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}Z",
self.year,
self.month,
self.day,
self.hour,
self.minute,
self.second,
self.nanosecond / (1000 * 1000)
)
}
}
impl UtcDateTime {
pub fn from_unix_nanos(nanos: u128) -> Self {
let st = nanos as u64;
let nanosecond = (st % (1000 * 1000 * 1000)) as u32;
let seconds = (st - (nanosecond as u64)) / (1000 * 1000 * 1000);
let time = seconds % (24 * 60 * 60);
let second = (time % 60) as u8;
let minutes = (time - (second as u64)) / 60;
let minute = (minutes % 60) as u8;
let hour = ((minutes - (minute as u64)) / 60) as u8;
let mut days = (seconds - time) / (24 * 60 * 60);
let mut year: u32 = 1970;
fn leap_year(year: u32) -> bool {
(year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))
}
loop {
if leap_year(year) {
if days < 366 {
break;
}
days -= 366; } else if days < 365 {
break;
} else {
days -= 365; }
year += 1;
}
const MONTHS: [u8; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
let mut month: u8 = 0;
loop {
if month == 1 {
if leap_year(year) {
if days < 29 {
break;
}
days -= 29;
month += 1;
continue;
} else if days < 28 {
break;
}
days -= 28;
month += 1;
continue;
}
if days < MONTHS[month as usize] as u64 {
break;
}
days -= MONTHS[month as usize] as u64;
month += 1;
}
Self {
year,
month: month + 1,
day: (days + 1) as u8,
hour,
minute,
second,
nanosecond,
}
}
}