use core::sync::atomic::{AtomicU32, Ordering};
use super::{Duration, UnixInstant};
#[repr(transparent)]
#[derive(Default, Debug)]
pub struct AtomicUnixInstant {
secs: AtomicU32,
}
impl AtomicUnixInstant {
pub fn new(value: UnixInstant) -> Self {
Self {
secs: value.secs.into(),
}
}
pub fn now() -> Self {
Self::new(UnixInstant::now())
}
pub fn load(&self, ordering: Ordering) -> UnixInstant {
UnixInstant {
secs: self.secs.load(ordering),
}
}
pub fn store(&self, value: UnixInstant, ordering: Ordering) {
self.secs.store(value.secs, ordering)
}
pub fn swap(&self, value: UnixInstant, ordering: Ordering) -> UnixInstant {
UnixInstant {
secs: self.secs.swap(value.secs, ordering),
}
}
pub fn compare_exchange(
&self,
current: UnixInstant,
new: UnixInstant,
success: Ordering,
failure: Ordering,
) -> Result<UnixInstant, UnixInstant> {
self.secs
.compare_exchange(current.secs, new.secs, success, failure)
.map(|secs| UnixInstant { secs })
.map_err(|secs| UnixInstant { secs })
}
pub fn compare_exchange_weak(
&self,
current: UnixInstant,
new: UnixInstant,
success: Ordering,
failure: Ordering,
) -> Result<UnixInstant, UnixInstant> {
self.secs
.compare_exchange_weak(current.secs, new.secs, success, failure)
.map(|secs| UnixInstant { secs })
.map_err(|secs| UnixInstant { secs })
}
pub fn fetch_add(&self, value: Duration, ordering: Ordering) -> UnixInstant {
UnixInstant {
secs: self.secs.fetch_add(value.secs, ordering),
}
}
pub fn fetch_max(&self, value: UnixInstant, ordering: Ordering) -> UnixInstant {
UnixInstant {
secs: self.secs.fetch_max(value.secs, ordering),
}
}
pub fn fetch_min(&self, value: UnixInstant, ordering: Ordering) -> UnixInstant {
UnixInstant {
secs: self.secs.fetch_min(value.secs, ordering),
}
}
pub fn fetch_sub(&self, value: Duration, ordering: Ordering) -> UnixInstant {
UnixInstant {
secs: self.secs.fetch_sub(value.secs, ordering),
}
}
}
impl From<UnixInstant> for AtomicUnixInstant {
fn from(other: UnixInstant) -> Self {
AtomicUnixInstant {
secs: other.secs.into(),
}
}
}
pub struct TryFromError {
kind: TryFromErrorKind,
}
enum TryFromErrorKind {
Overflow,
BeforeEpoch,
}
impl TryFromError {
const fn description(&self) -> &'static str {
match self.kind {
TryFromErrorKind::Overflow => "can not convert to UnixInstant: value is too big",
TryFromErrorKind::BeforeEpoch => {
"can not convert to UnixInstant: value is before unix epoch"
}
}
}
}
impl core::fmt::Display for TryFromError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.description().fmt(f)
}
}
impl TryFrom<std::time::SystemTime> for AtomicUnixInstant {
type Error = TryFromError;
fn try_from(other: std::time::SystemTime) -> Result<Self, Self::Error> {
let other = other
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.map_err(|_| TryFromError {
kind: TryFromErrorKind::BeforeEpoch,
})?
.as_secs();
if other > u32::MAX as u64 {
Err(TryFromError {
kind: TryFromErrorKind::Overflow,
})
} else {
Ok(Self {
secs: (other as u32).into(),
})
}
}
}
impl TryFrom<crate::precise::UnixInstant> for AtomicUnixInstant {
type Error = TryFromError;
fn try_from(other: crate::precise::UnixInstant) -> Result<Self, Self::Error> {
let other = other.ns / crate::precise::Duration::SECOND.as_nanos();
if other > u32::MAX as u64 {
Err(TryFromError {
kind: TryFromErrorKind::Overflow,
})
} else {
Ok(Self {
secs: (other as u32).into(),
})
}
}
}