#[repr(C)]
#[derive(Clone, Copy)]
pub union Duration {
duration: std::time::Duration,
payload: CDuration,
}
static_assertions::assert_eq_size!(Duration, std::time::Duration);
static_assertions::assert_eq_size!(Duration, CDuration);
impl std::fmt::Debug for Duration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if unsafe { self.payload }.is_valid() {
write!(f, "{:?}", unsafe { self.duration })
} else {
write!(f, "Duration({:?})", unsafe { self.payload })
}
}
}
impl std::hash::Hash for Duration {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
unsafe { self.duration }.hash(state);
}
}
impl PartialEq for Duration {
fn eq(&self, other: &Self) -> bool {
unsafe { self.payload.eq(&other.payload) }
}
}
impl PartialOrd for Duration {
fn partial_cmp(&self, other: &Self) -> std::option::Option<std::cmp::Ordering> {
if unsafe { !self.payload.is_valid() || !other.payload.is_valid() } {
return None;
}
unsafe { self.duration.partial_cmp(&other.duration) }
}
}
impl Duration {
pub fn from_duration(duration: std::time::Duration) -> Self {
let mut uninit = std::mem::MaybeUninit::<Duration>::uninit();
unsafe {
uninit.as_mut_ptr().write(Self { duration });
uninit.assume_init()
}
}
pub fn into_duration(self) -> std::option::Option<std::time::Duration> {
if unsafe { self.payload }.is_valid() {
Some(unsafe { self.duration })
} else {
None
}
}
pub fn as_duration(&self) -> std::option::Option<&std::time::Duration> {
if unsafe { self.payload }.is_valid() {
Some(unsafe { &self.duration })
} else {
None
}
}
pub fn as_mut_duration(&mut self) -> std::option::Option<&mut std::time::Duration> {
if unsafe { self.payload }.is_valid() {
Some(unsafe { &mut self.duration })
} else {
None
}
}
pub unsafe fn into_duration_unchecked(self) -> std::time::Duration {
self.duration
}
pub unsafe fn as_duration_unchecked(&self) -> &std::time::Duration {
&self.duration
}
pub unsafe fn as_mut_duration_unchecked(&mut self) -> &mut std::time::Duration {
&mut self.duration
}
#[cfg(test)]
pub fn as_c_ptr(&self) -> *const libc::c_void {
unsafe { &raw const self.payload as *const _ }
}
#[cfg(test)]
pub fn as_c_mut_ptr(&mut self) -> *mut libc::c_void {
unsafe { &raw mut self.payload as *mut _ }
}
}
impl From<std::time::Duration> for Duration {
fn from(duration: std::time::Duration) -> Self {
Self::from_duration(duration)
}
}
impl From<CDuration> for Duration {
fn from(payload: CDuration) -> Self {
Self { payload }
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union Instant {
instant: std::time::Instant,
payload: CDuration,
}
static_assertions::assert_eq_size!(Instant, std::time::Instant);
static_assertions::assert_eq_size!(Instant, CDuration);
impl std::fmt::Debug for Instant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if unsafe { self.payload }.is_valid() {
write!(f, "{:?}", unsafe { self.instant })
} else {
write!(f, "Instant({:?})", unsafe { self.payload })
}
}
}
impl std::hash::Hash for Instant {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
unsafe { self.instant }.hash(state);
}
}
impl PartialEq for Instant {
fn eq(&self, other: &Self) -> bool {
unsafe { self.payload.eq(&other.payload) }
}
}
impl PartialOrd for Instant {
fn partial_cmp(&self, other: &Self) -> std::option::Option<std::cmp::Ordering> {
if unsafe { !self.payload.is_valid() || !other.payload.is_valid() } {
return None;
}
unsafe { self.instant.partial_cmp(&other.instant) }
}
}
impl Instant {
pub fn from_instant(instant: std::time::Instant) -> Self {
let mut uninit = std::mem::MaybeUninit::<Self>::uninit();
unsafe {
uninit.as_mut_ptr().write(Self { instant });
uninit.assume_init()
}
}
pub fn into_instant(self) -> std::option::Option<std::time::Instant> {
if unsafe { self.payload }.is_valid() {
Some(unsafe { self.instant })
} else {
None
}
}
pub fn as_instant(&self) -> std::option::Option<&std::time::Instant> {
if unsafe { self.payload }.is_valid() {
Some(unsafe { &self.instant })
} else {
None
}
}
pub fn as_mut_instant(&mut self) -> std::option::Option<&mut std::time::Instant> {
if unsafe { self.payload }.is_valid() {
Some(unsafe { &mut self.instant })
} else {
None
}
}
pub unsafe fn into_instant_unchecked(self) -> std::time::Instant {
self.instant
}
pub unsafe fn as_instant_unchecked(&self) -> &std::time::Instant {
&self.instant
}
pub unsafe fn as_mut_instant_unchecked(&mut self) -> &mut std::time::Instant {
&mut self.instant
}
#[cfg(test)]
pub fn as_c_ptr(&self) -> *const libc::c_void {
unsafe { &raw const self.payload as *const _ }
}
#[cfg(test)]
pub fn as_c_mut_ptr(&mut self) -> *mut libc::c_void {
unsafe { &raw mut self.payload as *mut _ }
}
}
impl From<std::time::Instant> for Instant {
fn from(instant: std::time::Instant) -> Self {
Self::from_instant(instant)
}
}
impl From<CDuration> for Instant {
fn from(payload: CDuration) -> Self {
Self { payload }
}
}
#[derive(Clone, Copy)]
#[repr(C)]
struct CDuration {
pub secs: u64,
pub nanos: u32,
_padding: u32,
}
impl CDuration {
const NONE_NANOS: u32 = (-1i32) as u32;
fn is_valid(&self) -> bool {
self.nanos < 1_000_000_000
}
fn is_none(&self) -> bool {
self.nanos == Self::NONE_NANOS
}
}
impl std::fmt::Debug for CDuration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{{ secs: {}, nanos: {} }}", self.secs, self.nanos)
}
}
impl PartialEq for CDuration {
fn eq(&self, other: &Self) -> bool {
self.secs == other.secs && self.nanos == other.nanos
}
}
#[derive(Debug)]
#[repr(C)]
pub struct Option<T>(CDuration, std::marker::PhantomData<T>);
impl<T> Option<T> {
pub fn is_none(&self) -> bool {
self.0.is_none()
}
pub fn is_some(&self) -> bool {
!self.is_none()
}
}
#[allow(private_bounds)]
impl<T: From<CDuration>> Option<T> {
pub fn unwrap(self) -> T {
T::from(self.0)
}
#[track_caller]
pub fn expect(self, msg: &str) -> T {
if self.0.is_none() {
panic!("{}", msg);
}
T::from(self.0)
}
}
impl<T: PartialEq> PartialEq for Option<T> {
fn eq(&self, other: &Self) -> bool {
let l_is_none = self.is_none();
let r_is_none = other.is_none();
if l_is_none || r_is_none {
l_is_none == r_is_none
} else {
self.0.eq(&other.0)
}
}
}
impl Option<Duration> {
pub fn into_duration(self) -> std::option::Option<std::time::Duration> {
if self.0.is_valid() {
Some(Duration { payload: self.0 }.into_duration().unwrap())
} else {
None
}
}
}
impl Option<Instant> {
pub fn into_instant(self) -> std::option::Option<std::time::Instant> {
if self.0.is_valid() {
Some(Instant { payload: self.0 }.into_instant().unwrap())
} else {
None
}
}
}