Skip to main content

harmos_runtime/storage/
consumer.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12/* === Re-Exports === */
13
14/* === Imports === */
15
16// Standard Library Imports
17use std::any::Any;
18use std::future::Future;
19use std::marker::PhantomData;
20use std::ops::Bound;
21use std::pin::Pin;
22use std::sync::Arc;
23// Third Party Imports
24
25// Local Imports
26use crate::{Application, state::At, state::Entry, state::Position, state::Recorded};
27
28/* === Constants === */
29
30/* === Macros === */
31
32/* === Type Aliases === */
33
34/* === Structs === */
35
36#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct Cursor(pub u64);
38
39pub struct Batch<A: Application> {
40    pub(crate) rows: Vec<(Cursor, crate::streams::Definition, Position, Arc<dyn Any + Send + Sync>)>,
41    pub(crate) reaches: Cursor,
42    pub(crate) incomplete: Vec<crate::streams::Definition>,
43    pub(crate) application: PhantomData<fn() -> A>,
44}
45
46/* === Enums === */
47
48/* === Traits === */
49
50pub trait JournalConsumer<A: Application>: Send + 'static {
51    fn resume(&self) -> Position;
52
53    fn drain(&mut self, entries: Vec<Arc<Entry<Recorded<A>>>>, applied: Position) -> impl Future<Output = Position> + Send;
54
55    fn flush(&mut self) -> impl Future<Output = ()> + Send {
56        async {}
57    }
58
59    fn redelivered(&mut self, stored: &[(Position, Vec<u8>)]) {
60        let _ = stored;
61    }
62}
63
64pub(crate) trait Attached<A: Application>: Send {
65    fn resume(&self) -> Position;
66
67    fn drain(&mut self, entries: Vec<Arc<Entry<Recorded<A>>>>, applied: Position) -> Pin<Box<dyn Future<Output = Position> + Send + '_>>;
68
69    fn flush(&mut self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
70
71    fn redelivered(&mut self, stored: &[(Position, Vec<u8>)]);
72}
73
74pub trait StreamConsumer<A: Application>: Send + 'static {
75    fn resume(&self) -> Cursor;
76
77    fn selections(&self) -> Vec<crate::streams::Definition> {
78        Vec::new()
79    }
80
81    fn drain(&mut self, batch: Batch<A>) -> impl Future<Output = Cursor> + Send;
82
83    fn flush(&mut self) -> impl Future<Output = ()> + Send {
84        async {}
85    }
86}
87
88pub trait Series<A: Application>: StreamConsumer<A> {
89    fn reader(
90        &mut self, _stream: crate::streams::Definition, _track: &[String], _start: Bound<Position>, _end: Bound<Position>,
91        _limits: crate::streams::ReadLimits,
92    ) -> impl Future<Output = Result<Box<dyn crate::streams::RowSource>, crate::streams::ReadError>> + Send {
93        async { Err(crate::streams::ReadError::Unsupported) }
94    }
95
96    // Rows are spelled out rather than aliased: the census is the list of
97    // names an author learns, and an erased row belongs to this signature
98    // rather than beside them.
99    #[allow(clippy::type_complexity)]
100    fn rows(
101        &mut self, stream: crate::streams::Definition, track: &[String], start: Bound<Position>, end: Bound<Position>,
102    ) -> impl Future<Output = Result<Vec<At<Arc<dyn Any + Send + Sync>>>, crate::streams::BeneathWindow>> + Send;
103
104    fn buckets(
105        &mut self, stream: crate::streams::Definition, track: &[String], start: Bound<u64>, end: Bound<u64>, budget: usize,
106    ) -> impl Future<Output = Result<Vec<crate::streams::Bucket>, crate::streams::BeneathWindow>> + Send;
107
108    fn aggregate(
109        &mut self, stream: crate::streams::Definition, track: &[String], start: Bound<u64>, end: Bound<u64>, kind: crate::Aggregate,
110    ) -> impl Future<Output = Result<Vec<crate::streams::Aggregated>, crate::streams::BeneathWindow>> + Send;
111
112    fn seal(&mut self, stream: crate::streams::Definition, track: &[String]) -> impl Future<Output = Position> + Send;
113}
114
115pub(crate) trait Recording<A: Application>: Send {
116    fn resume(&self) -> Cursor;
117
118    fn selections(&self) -> Vec<crate::streams::Definition>;
119
120    fn drain(&mut self, batch: Batch<A>) -> Pin<Box<dyn Future<Output = Cursor> + Send + '_>>;
121
122    fn flush(&mut self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
123}
124
125pub(crate) trait Serving<A: Application>: Recording<A> {
126    #[allow(clippy::type_complexity)]
127    fn reader<'read>(
128        &'read mut self, stream: crate::streams::Definition, track: &'read [String], start: Bound<Position>, end: Bound<Position>,
129        limits: crate::streams::ReadLimits,
130    ) -> Pin<Box<dyn Future<Output = Result<Box<dyn crate::streams::RowSource>, crate::streams::ReadError>> + Send + 'read>>;
131
132    #[allow(clippy::type_complexity)]
133    fn rows<'read>(
134        &'read mut self, stream: crate::streams::Definition, track: &'read [String], start: Bound<Position>, end: Bound<Position>,
135    ) -> Pin<Box<dyn Future<Output = Result<Vec<At<Arc<dyn Any + Send + Sync>>>, crate::streams::BeneathWindow>> + Send + 'read>>;
136
137    #[allow(clippy::type_complexity)]
138    fn buckets<'read>(
139        &'read mut self, stream: crate::streams::Definition, track: &'read [String], start: Bound<u64>, end: Bound<u64>, budget: usize,
140    ) -> Pin<Box<dyn Future<Output = Result<Vec<crate::streams::Bucket>, crate::streams::BeneathWindow>> + Send + 'read>>;
141
142    #[allow(clippy::type_complexity)]
143    fn aggregate<'read>(
144        &'read mut self, stream: crate::streams::Definition, track: &'read [String], start: Bound<u64>, end: Bound<u64>,
145        kind: crate::Aggregate,
146    ) -> Pin<Box<dyn Future<Output = Result<Vec<crate::streams::Aggregated>, crate::streams::BeneathWindow>> + Send + 'read>>;
147
148    fn seal<'read>(
149        &'read mut self, stream: crate::streams::Definition, track: &'read [String],
150    ) -> Pin<Box<dyn Future<Output = Position> + Send + 'read>>;
151}
152
153/* === Implementations === */
154
155impl<A: Application, C: JournalConsumer<A>> Attached<A> for C {
156    fn resume(&self) -> Position {
157        JournalConsumer::resume(self)
158    }
159
160    fn drain(&mut self, entries: Vec<Arc<Entry<Recorded<A>>>>, applied: Position) -> Pin<Box<dyn Future<Output = Position> + Send + '_>> {
161        Box::pin(JournalConsumer::drain(self, entries, applied))
162    }
163
164    fn flush(&mut self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
165        Box::pin(JournalConsumer::flush(self))
166    }
167
168    fn redelivered(&mut self, stored: &[(Position, Vec<u8>)]) {
169        JournalConsumer::redelivered(self, stored);
170    }
171}
172
173impl Cursor {
174    pub const ORIGIN: Self = Self(0);
175}
176
177impl<A: Application> Batch<A> {
178    pub fn reaches(&self) -> Cursor {
179        self.reaches
180    }
181
182    pub fn incomplete(&self) -> &[crate::streams::Definition] {
183        &self.incomplete
184    }
185
186    pub fn publications(&self) -> impl Iterator<Item = (&crate::streams::Definition, Cursor, At<&crate::streams::PublicationRow>)> + '_ {
187        self.rows.iter().filter_map(|(cursor, definition, position, row)| {
188            definition.owner()?;
189            let payload = crate::streams::row_value::<crate::streams::PublicationRow>(row.as_ref())?;
190            Some((definition, *cursor, At { value: payload, position: *position }))
191        })
192    }
193
194    pub fn select<S: crate::streams::Stream<A>>(&self) -> impl Iterator<Item = At<S>> + '_ {
195        self.rows.iter().filter_map(|(_, definition, position, row)| {
196            if definition.id() != S::ID || definition.version() != S::VERSION {
197                return None;
198            }
199
200            row.downcast_ref::<S>().cloned().map(|value| At { value, position: *position })
201        })
202    }
203}
204
205impl<A: Application, S: Series<A>> Serving<A> for S {
206    #[allow(clippy::type_complexity)]
207    fn reader<'read>(
208        &'read mut self, stream: crate::streams::Definition, track: &'read [String], start: Bound<Position>, end: Bound<Position>,
209        limits: crate::streams::ReadLimits,
210    ) -> Pin<Box<dyn Future<Output = Result<Box<dyn crate::streams::RowSource>, crate::streams::ReadError>> + Send + 'read>> {
211        Box::pin(Series::reader(self, stream, track, start, end, limits))
212    }
213
214    fn rows<'read>(
215        &'read mut self, stream: crate::streams::Definition, track: &'read [String], start: Bound<Position>, end: Bound<Position>,
216    ) -> Pin<Box<dyn Future<Output = Result<Vec<At<Arc<dyn Any + Send + Sync>>>, crate::streams::BeneathWindow>> + Send + 'read>> {
217        Box::pin(Series::rows(self, stream, track, start, end))
218    }
219
220    fn buckets<'read>(
221        &'read mut self, stream: crate::streams::Definition, track: &'read [String], start: Bound<u64>, end: Bound<u64>, budget: usize,
222    ) -> Pin<Box<dyn Future<Output = Result<Vec<crate::streams::Bucket>, crate::streams::BeneathWindow>> + Send + 'read>> {
223        Box::pin(Series::buckets(self, stream, track, start, end, budget))
224    }
225
226    fn aggregate<'read>(
227        &'read mut self, stream: crate::streams::Definition, track: &'read [String], start: Bound<u64>, end: Bound<u64>,
228        kind: crate::Aggregate,
229    ) -> Pin<Box<dyn Future<Output = Result<Vec<crate::streams::Aggregated>, crate::streams::BeneathWindow>> + Send + 'read>> {
230        Box::pin(Series::aggregate(self, stream, track, start, end, kind))
231    }
232
233    fn seal<'read>(
234        &'read mut self, stream: crate::streams::Definition, track: &'read [String],
235    ) -> Pin<Box<dyn Future<Output = Position> + Send + 'read>> {
236        Box::pin(Series::seal(self, stream, track))
237    }
238}
239
240impl<A: Application, C: StreamConsumer<A>> Recording<A> for C {
241    fn resume(&self) -> Cursor {
242        StreamConsumer::resume(self)
243    }
244
245    fn selections(&self) -> Vec<crate::streams::Definition> {
246        StreamConsumer::selections(self)
247    }
248
249    fn drain(&mut self, batch: Batch<A>) -> Pin<Box<dyn Future<Output = Cursor> + Send + '_>> {
250        Box::pin(StreamConsumer::drain(self, batch))
251    }
252
253    fn flush(&mut self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
254        Box::pin(StreamConsumer::flush(self))
255    }
256}
257
258/* === Public Functions === */
259
260/* === Private Functions === */
261
262/* === Tests === */