use core::time::Duration;
use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
#[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, MlsSize, MlsEncode, MlsDecode,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[repr(transparent)]
pub struct MlsTime {
seconds: u64,
}
impl MlsTime {
pub fn from_duration_since_epoch(duration: Duration) -> MlsTime {
Self::from(duration)
}
pub fn seconds_since_epoch(&self) -> u64 {
self.seconds
}
}
impl core::ops::Sub<MlsTime> for MlsTime {
type Output = Duration;
fn sub(self, rhs: Self) -> Duration {
Duration::from_secs(self.seconds - rhs.seconds)
}
}
impl core::ops::Sub<Duration> for MlsTime {
type Output = MlsTime;
fn sub(self, rhs: Duration) -> MlsTime {
MlsTime::from(self.seconds - rhs.as_secs())
}
}
impl core::ops::Add<Duration> for MlsTime {
type Output = MlsTime;
fn add(self, rhs: Duration) -> MlsTime {
MlsTime::from(self.seconds + rhs.as_secs())
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
impl MlsTime {
pub fn now() -> Self {
Self {
seconds: std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
}
}
}
impl From<u64> for MlsTime {
fn from(value: u64) -> Self {
Self { seconds: value }
}
}
impl From<Duration> for MlsTime {
fn from(value: Duration) -> MlsTime {
Self {
seconds: value.as_secs(),
}
}
}
impl From<MlsTime> for Duration {
fn from(value: MlsTime) -> Duration {
Duration::from_secs(value.seconds)
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
#[derive(Debug, thiserror::Error)]
#[error("Overflow while adding {0:?}")]
pub struct TimeOverflow(Duration);
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
impl TryFrom<MlsTime> for std::time::SystemTime {
type Error = TimeOverflow;
fn try_from(value: MlsTime) -> Result<std::time::SystemTime, Self::Error> {
let duration = Duration::from(value);
std::time::SystemTime::UNIX_EPOCH
.checked_add(duration)
.ok_or(TimeOverflow(duration))
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
impl TryFrom<std::time::SystemTime> for MlsTime {
type Error = std::time::SystemTimeError;
fn try_from(value: std::time::SystemTime) -> Result<MlsTime, Self::Error> {
let duration = value.duration_since(std::time::SystemTime::UNIX_EPOCH)?;
Ok(MlsTime::from(duration))
}
}
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
#[wasm_bindgen(inline_js = r#"
export function date_now() {
return Date.now();
}"#)]
extern "C" {
fn date_now() -> f64;
}
#[cfg(all(target_arch = "wasm32", target_os = "emscripten"))]
extern "C" {
#[link_name = "emscripten_date_now"]
fn date_now() -> f64;
}
#[cfg(target_arch = "wasm32")]
impl MlsTime {
pub fn now() -> Self {
Self {
seconds: (unsafe { date_now() } / 1000.0) as u64,
}
}
}