use std::fmt::Debug;
use spacetimedb_lib::{TimeDuration, Timestamp};
use spacetimedb_sats::{
algebraic_value::de::{ValueDeserializeError, ValueDeserializer},
de::Deserialize,
impl_st,
ser::Serialize,
sum_type::{SCHEDULE_AT_INTERVAL_TAG, SCHEDULE_AT_TIME_TAG},
AlgebraicType, AlgebraicValue,
};
#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub enum ScheduleAt {
Interval(TimeDuration),
Time(Timestamp),
}
impl_st!([] ScheduleAt, ScheduleAt::get_type());
impl ScheduleAt {
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub fn to_duration_from(&self, from: Timestamp) -> std::time::Duration {
use std::time::Duration;
match self {
ScheduleAt::Time(time) => time.duration_since(from).unwrap_or(Duration::ZERO),
ScheduleAt::Interval(dur) => dur.to_duration_abs(),
}
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub fn to_timestamp_from(&self, from: Timestamp) -> Timestamp {
match *self {
ScheduleAt::Time(time) => time,
ScheduleAt::Interval(dur) => from + dur.abs(),
}
}
pub fn get_type() -> AlgebraicType {
AlgebraicType::sum([
(SCHEDULE_AT_INTERVAL_TAG, AlgebraicType::time_duration()),
(SCHEDULE_AT_TIME_TAG, AlgebraicType::timestamp()),
])
}
}
impl From<TimeDuration> for ScheduleAt {
fn from(value: TimeDuration) -> Self {
ScheduleAt::Interval(value)
}
}
impl From<std::time::Duration> for ScheduleAt {
fn from(value: std::time::Duration) -> Self {
ScheduleAt::Interval(TimeDuration::from_duration(value))
}
}
impl From<std::time::SystemTime> for ScheduleAt {
fn from(value: std::time::SystemTime) -> Self {
Timestamp::from(value).into()
}
}
impl From<crate::Timestamp> for ScheduleAt {
fn from(value: crate::Timestamp) -> Self {
ScheduleAt::Time(value)
}
}
impl TryFrom<AlgebraicValue> for ScheduleAt {
type Error = ValueDeserializeError;
fn try_from(value: AlgebraicValue) -> Result<Self, Self::Error> {
ScheduleAt::deserialize(ValueDeserializer::new(value))
}
}
#[cfg(test)]
mod tests {
use super::*;
use spacetimedb_sats::bsatn;
#[test]
fn test_bsatn_roundtrip() {
let schedule_at = ScheduleAt::Interval(TimeDuration::from_micros(10000));
let ser = bsatn::to_vec(&schedule_at).unwrap();
let de = bsatn::from_slice(&ser).unwrap();
assert_eq!(schedule_at, de);
}
#[test]
fn schedule_at_is_special() {
assert!(ScheduleAt::get_type().is_special());
}
}