use std::fmt; use crate::clock::DateTime; #[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize)] pub struct Instant { pub at: DateTime, #[serde(skip)] pub sequence: Sequence, } impl Instant { pub fn new(at: DateTime, sequence: Sequence) -> Self { Self { at, sequence } } pub fn optional(at: Option, sequence: Option) -> Option { at.zip(sequence) .map(|(at, sequence)| Self::new(at, sequence)) } } impl From for Sequence { fn from(instant: Instant) -> Self { instant.sequence } } #[derive( Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize, sqlx::Type, )] #[serde(transparent)] #[sqlx(transparent)] pub struct Sequence(i64); impl fmt::Display for Sequence { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self(value) = self; value.fmt(f) } } impl Sequence { pub fn up_to(resume_point: P) -> impl for<'e> Fn(&'e E) -> bool + Clone where P: Into, E: Sequenced, { let resume_point = resume_point.into(); move |event| event.sequence() <= resume_point } pub fn after(resume_point: P) -> impl for<'e> Fn(&'e E) -> bool + Clone where P: Into, E: Sequenced, { let resume_point = resume_point.into(); move |event| resume_point < event.sequence() } pub fn start_from(resume_point: P) -> impl for<'e> Fn(&'e E) -> bool + Clone where P: Into, E: Sequenced, { let resume_point = resume_point.into(); move |event| resume_point <= event.sequence() } pub fn merge(a: &E, b: &E) -> bool where E: Sequenced, { a.sequence() < b.sequence() } } pub trait Sequenced { fn instant(&self) -> Instant; fn at(&self) -> DateTime { self.instant().at } fn sequence(&self) -> Sequence { self.instant().into() } } impl Sequenced for &E where E: Sequenced, { fn instant(&self) -> Instant { (*self).instant() } fn sequence(&self) -> Sequence { (*self).sequence() } }