summaryrefslogtreecommitdiff
path: root/src/event/sequence.rs
blob: 9a0ea5d3413aaf702502085964ca64e5c590585a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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<DateTime>, sequence: Option<Sequence>) -> Option<Self> {
        at.zip(sequence)
            .map(|(at, sequence)| Self::new(at, sequence))
    }
}

impl From<Instant> 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<P, E>(resume_point: P) -> impl for<'e> Fn(&'e E) -> bool + Clone
    where
        P: Into<Self>,
        E: Sequenced,
    {
        let resume_point = resume_point.into();
        move |event| event.sequence() <= resume_point
    }

    pub fn after<P, E>(resume_point: P) -> impl for<'e> Fn(&'e E) -> bool + Clone
    where
        P: Into<Self>,
        E: Sequenced,
    {
        let resume_point = resume_point.into();
        move |event| resume_point < event.sequence()
    }

    pub fn start_from<P, E>(resume_point: P) -> impl for<'e> Fn(&'e E) -> bool + Clone
    where
        P: Into<Self>,
        E: Sequenced,
    {
        let resume_point = resume_point.into();
        move |event| resume_point <= event.sequence()
    }

    pub fn merge<E>(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<E> Sequenced for &E
where
    E: Sequenced,
{
    fn instant(&self) -> Instant {
        (*self).instant()
    }

    fn sequence(&self) -> Sequence {
        (*self).sequence()
    }
}