use core::sync::atomic::{AtomicU64, Ordering};
use super::{Duration, UnixInstant};
#[repr(transparent)]
#[derive(Default, Debug)]
pub struct AtomicUnixInstant {
ns: AtomicU64,
}
impl AtomicUnixInstant {
pub fn new(value: UnixInstant) -> Self {
Self {
ns: value.ns.into(),
}
}
pub fn now() -> Self {
Self::new(UnixInstant::now())
}
pub fn load(&self, ordering: Ordering) -> UnixInstant {
UnixInstant {
ns: self.ns.load(ordering),
}
}
pub fn store(&self, value: UnixInstant, ordering: Ordering) {
self.ns.store(value.ns, ordering)
}
pub fn swap(&self, value: UnixInstant, ordering: Ordering) -> UnixInstant {
UnixInstant {
ns: self.ns.swap(value.ns, ordering),
}
}
pub fn compare_exchange(
&self,
current: UnixInstant,
new: UnixInstant,
success: Ordering,
failure: Ordering,
) -> Result<UnixInstant, UnixInstant> {
self.ns
.compare_exchange(current.ns, new.ns, success, failure)
.map(|ns| UnixInstant { ns })
.map_err(|ns| UnixInstant { ns })
}
pub fn compare_exchange_weak(
&self,
current: UnixInstant,
new: UnixInstant,
success: Ordering,
failure: Ordering,
) -> Result<UnixInstant, UnixInstant> {
self.ns
.compare_exchange_weak(current.ns, new.ns, success, failure)
.map(|ns| UnixInstant { ns })
.map_err(|ns| UnixInstant { ns })
}
pub fn fetch_add(&self, value: Duration, ordering: Ordering) -> UnixInstant {
UnixInstant {
ns: self.ns.fetch_add(value.ns, ordering),
}
}
pub fn fetch_max(&self, value: UnixInstant, ordering: Ordering) -> UnixInstant {
UnixInstant {
ns: self.ns.fetch_max(value.ns, ordering),
}
}
pub fn fetch_min(&self, value: UnixInstant, ordering: Ordering) -> UnixInstant {
UnixInstant {
ns: self.ns.fetch_min(value.ns, ordering),
}
}
pub fn fetch_sub(&self, value: Duration, ordering: Ordering) -> UnixInstant {
UnixInstant {
ns: self.ns.fetch_sub(value.ns, ordering),
}
}
}
impl From<UnixInstant> for AtomicUnixInstant {
fn from(other: UnixInstant) -> Self {
AtomicUnixInstant {
ns: other.ns.into(),
}
}
}
impl From<crate::coarse::UnixInstant> for AtomicUnixInstant {
fn from(other: crate::coarse::UnixInstant) -> Self {
Self {
ns: (other.secs as u64 * super::Duration::SECOND.as_nanos()).into(),
}
}
}
#[derive(Debug)]
pub struct TryFromError {
kind: TryFromErrorKind,
}
#[derive(Debug)]
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 std::error::Error for TryFromError {}
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_nanos();
if other > u64::MAX as u128 {
Err(TryFromError {
kind: TryFromErrorKind::Overflow,
})
} else {
Ok(Self {
ns: (other as u64).into(),
})
}
}
}