1use std::collections::{BTreeMap, VecDeque};
18use std::fmt;
19use std::future::Future;
20use std::num::NonZeroUsize;
21use std::pin::Pin;
22use std::sync::Arc;
23use std::task::{Context, Poll};
24use futures_core::Stream;
26use tokio::sync::{mpsc, oneshot, watch};
27use super::TrackedState;
29use super::entry::{At, Entry, Link, Position, PrincipalId};
30use super::envelope::{Envelope, Recorded};
31use super::transaction::dispatch::Dispatch;
32use super::transaction::{DecodeError, Inverting};
33use crate::Application;
34use crate::error::Error;
35
36type Predicate<A> = Arc<dyn Fn(&<A as Application>::Transaction) -> bool + Send + Sync>;
43
44type Step<A, X> = Pin<Box<dyn Future<Output = (Parts<A>, Result<Vec<Entry<X>>, Error>)> + Send>>;
45
46pub struct Origin<S> {
49 pub value: S,
50 pub position: Position,
51}
52
53pub(crate) struct Reads<A: Application> {
54 sender: mpsc::Sender<ReadRequest<A>>,
55}
56
57pub struct Focus<A: Application> {
58 predicate: Option<Predicate<A>>,
59}
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
62pub struct Reversals {
63 pub undoable: bool,
64 pub redoable: bool,
65}
66
67pub(crate) struct Undoable<A: Application> {
68 pub(crate) principal: PrincipalId,
69 pub(crate) forward: Arc<A::Transaction>,
70 pub(crate) inverse: Option<Arc<A::Transaction>>,
71 pub(crate) undone: Option<Position>,
72}
73
74pub(crate) struct Undos<A: Application> {
75 pub(crate) entries: BTreeMap<Position, Undoable<A>>,
76}
77
78pub(crate) struct Tail<A: Application> {
79 pub(crate) entries: VecDeque<Arc<Entry<Recorded<A>>>>,
80 capacity: usize,
81 floor: Position,
82}
83
84pub(crate) struct SharedPage<A: Application> {
85 pub(crate) entries: Vec<Arc<Entry<Recorded<A>>>>,
86 pub(crate) reaches: Position,
87}
88
89struct Parts<A: Application> {
90 tracked: Arc<TrackedState<A>>,
91 frontier: Position,
92 doorbell: watch::Receiver<Position>,
93}
94
95struct Watching<A: Application, X> {
96 parts: Option<Parts<A>>,
97 step: Option<Step<A, X>>,
98 pending: VecDeque<Entry<X>>,
99 done: bool,
100}
101
102pub(crate) enum ReadRequest<A: Application> {
105 Entries { after: Position, through: Position, reply: oneshot::Sender<Result<Vec<Entry<Recorded<A>>>, Error>> },
106 State { origin: Origin<A::State>, at: Position, reply: oneshot::Sender<Result<At<A::State>, Error>> },
107}
108
109pub(crate) trait ReplayPayload<A: Application>: Sized {
112 fn prepared(&self) -> Option<crate::state::Prepared> {
113 None
114 }
115
116 fn forward(&self) -> Option<Arc<A::Transaction>>;
117 fn restore(
118 envelope: Envelope<Self>, catalog: Option<&Dispatch<A, Self>>, state: &mut A::State,
119 ) -> Result<Option<Recorded<A>>, DecodeError>;
120}
121
122impl<S> Origin<S> {
125 pub fn initial(value: S) -> Self {
126 Self { value, position: Position::ORIGIN }
127 }
128
129 pub fn at(value: S, position: Position) -> Self {
130 Self { value, position }
131 }
132}
133
134impl<S> From<S> for Origin<S> {
135 fn from(value: S) -> Self {
136 Self::initial(value)
137 }
138}
139
140impl<S> From<At<S>> for Origin<S> {
141 fn from(origin: At<S>) -> Self {
142 Self::at(origin.value, origin.position)
143 }
144}
145
146impl<A: Application> Reads<A> {
147 pub(crate) fn channel(capacity: usize) -> (Self, mpsc::Receiver<ReadRequest<A>>) {
148 let (sender, receiver) = mpsc::channel(capacity.max(1));
149
150 (Self { sender }, receiver)
151 }
152
153 pub(crate) async fn entries(&self, after: Position, through: Position) -> Result<Vec<Entry<Recorded<A>>>, Error> {
154 let (reply, answer) = oneshot::channel();
155 self.sender.send(ReadRequest::Entries { after, through, reply }).await.map_err(|_| Error::BeyondTail)?;
156
157 answer.await.map_err(|_| Error::Unavailable)?
158 }
159
160 pub(crate) async fn state(&self, origin: Origin<A::State>, at: Position) -> Result<At<A::State>, Error> {
161 if origin.position > at {
162 return Err(Error::OriginAhead);
163 }
164 if origin.position == at {
165 return Ok(At { value: origin.value, position: at });
166 }
167
168 let (reply, answer) = oneshot::channel();
169 self.sender.send(ReadRequest::State { origin, at, reply }).await.map_err(|_| Error::BeyondTail)?;
170
171 answer.await.map_err(|_| Error::Unavailable)?
172 }
173}
174
175impl<A: Application> Clone for Reads<A> {
176 fn clone(&self) -> Self {
177 Self { sender: self.sender.clone() }
178 }
179}
180
181impl<A: Application> Focus<A> {
182 pub fn all() -> Self {
183 Self { predicate: None }
184 }
185
186 pub fn matching(predicate: impl Fn(&A::Transaction) -> bool + Send + Sync + 'static) -> Self {
187 Self { predicate: Some(Arc::new(predicate)) }
188 }
189
190 fn admits(&self, transaction: &A::Transaction) -> bool {
191 self.predicate.as_ref().is_none_or(|predicate| predicate(transaction))
192 }
193}
194
195impl<A: Application> Clone for Focus<A> {
196 fn clone(&self) -> Self {
197 Self { predicate: self.predicate.clone() }
198 }
199}
200
201impl<A: Application> fmt::Debug for Focus<A> {
202 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
203 formatter.write_str(match self.predicate {
204 Some(_) => "Focus::matching(..)",
205 None => "Focus::all()",
206 })
207 }
208}
209
210impl<A: Application> Undos<A> {
211 pub(crate) fn record(
212 &mut self, position: Position, principal: Option<&PrincipalId>, link: Option<Link>, forward: &Arc<A::Transaction>,
213 inverse: Option<A::Transaction>,
214 ) {
215 match link {
216 Some(Link::UndoOf(original)) => {
217 if let Some(entry) = self.entries.get_mut(&original) {
218 entry.undone = Some(position);
219 }
220 }
221 Some(Link::RedoOf(original)) => {
222 if let Some(entry) = self.entries.get_mut(&original) {
223 entry.undone = None;
224 entry.inverse = inverse.map(Arc::new);
228 }
229 }
230 None => {
231 let Some(principal) = principal else {
232 return;
233 };
234 self.entries.retain(|_, entry| entry.principal != *principal || entry.undone.is_none());
240 self.entries.insert(
241 position,
242 Undoable { principal: principal.clone(), forward: Arc::clone(forward), inverse: inverse.map(Arc::new), undone: None },
243 );
244 }
245 }
246 }
247
248 pub(crate) fn undoable(&self, principal: &PrincipalId, focus: &Focus<A>) -> Option<(Position, Arc<A::Transaction>)> {
249 for (position, entry) in self.entries.iter().rev() {
250 if entry.principal != *principal {
251 continue;
252 }
253 if entry.undone.is_some() || !focus.admits(&entry.forward) {
254 continue;
255 }
256 let inverse = entry.inverse.as_ref()?;
257 return Some((*position, Arc::clone(inverse)));
258 }
259 None
260 }
261
262 pub(crate) fn redoable(&self, principal: &PrincipalId, focus: &Focus<A>) -> Option<(Position, Arc<A::Transaction>)> {
263 self.entries
264 .iter()
265 .filter(|(_, entry)| entry.principal == *principal && focus.admits(&entry.forward))
266 .filter_map(|(position, entry)| entry.undone.map(|at| (at, *position, Arc::clone(&entry.forward))))
267 .max_by_key(|(at, _position, _forward)| *at)
268 .map(|(_at, position, forward)| (position, forward))
269 }
270
271 pub(crate) fn reversals(&self, principal: &PrincipalId, focus: &Focus<A>) -> Reversals {
272 Reversals { undoable: self.undoable(principal, focus).is_some(), redoable: self.redoable(principal, focus).is_some() }
273 }
274}
275
276impl<A: Application> Default for Undos<A> {
277 fn default() -> Self {
278 Self { entries: BTreeMap::new() }
279 }
280}
281
282impl<A: Application> Tail<A> {
283 pub(crate) fn new(origin: Position, capacity: usize) -> Self {
284 Self { entries: VecDeque::new(), capacity: capacity.max(1), floor: origin }
285 }
286
287 pub(crate) fn recovered(frontier: Position, capacity: usize, entries: Vec<Arc<Entry<Recorded<A>>>>) -> Self {
288 if entries.is_empty() {
289 return Self::new(frontier, capacity);
290 }
291 let floor = entries.first().map_or(frontier, |entry| Position(entry.position.0.saturating_sub(1)));
292
293 Self { entries: entries.into(), capacity: capacity.max(1), floor }
294 }
295
296 pub(crate) fn push_group(&mut self, entries: Vec<Entry<Recorded<A>>>) -> Vec<Arc<Entry<Recorded<A>>>> {
297 while self.entries.len() + entries.len() > self.capacity && !self.entries.is_empty() {
298 let evicted = self.entries.pop_front().expect("nonempty tail");
299 let frontier = evicted.metadata.commit.map_or(evicted.position, |(_, end)| end);
300 self.floor = frontier;
301 while self.entries.front().is_some_and(|entry| entry.position <= frontier) {
302 self.entries.pop_front();
303 }
304 }
305 let entries: Vec<_> = entries.into_iter().map(Arc::new).collect();
306 self.entries.extend(entries.iter().cloned());
307 entries
308 }
309
310 pub(crate) fn splits_commit(&self, position: Position) -> bool {
311 self.entries.iter().any(|entry| entry.metadata.commit.is_some_and(|(first, end)| first <= position && position < end))
312 }
313
314 pub(crate) fn since(&self, after: Position) -> Result<Vec<Arc<Entry<Recorded<A>>>>, Error> {
315 if after < self.floor {
316 return Err(Error::BeyondTail);
317 }
318
319 Ok(self.entries.iter().filter(|entry| entry.position > after).map(Arc::clone).collect())
320 }
321
322 pub(crate) fn scan<X: Clone + 'static>(&self, after: Position) -> Result<(Vec<Entry<X>>, Position), Error> {
323 self.scan_through(after, Position(u64::MAX))
324 }
325
326 pub(crate) fn scan_through<X: Clone + 'static>(&self, after: Position, through: Position) -> Result<(Vec<Entry<X>>, Position), Error> {
327 let mut frontier = after;
328 let mut found = Vec::new();
329 loop {
330 let page = self.shared_page(frontier, through, NonZeroUsize::new(1024).unwrap())?;
331 if page.entries.is_empty() {
332 break;
333 }
334 frontier = page.reaches;
335 for entry in page.entries {
336 if let Some(value) = entry.value.select::<X>() {
337 found.push(Entry { prepared: None, position: entry.position, metadata: entry.metadata.clone(), value });
338 }
339 }
340 }
341
342 Ok((found, frontier))
343 }
344
345 pub(crate) fn shared_page(&self, after: Position, through: Position, max_rows: NonZeroUsize) -> Result<SharedPage<A>, Error> {
346 if after < self.floor {
347 return Err(Error::BeyondTail);
348 }
349 let start = self.entries.partition_point(|entry| entry.position <= after);
350 let count = max_rows.get().min(self.entries.len() - start);
351 let mut entries = Vec::with_capacity(count);
352 let mut reaches = after;
353 for entry in self.entries.iter().skip(start).take(count) {
354 if entry.position > through {
355 break;
356 }
357 reaches = entry.position;
358 entries.push(Arc::clone(entry));
359 }
360 Ok(SharedPage { entries, reaches })
361 }
362}
363
364impl<A: Application, X> Unpin for Watching<A, X> {}
365
366impl<A, X> Stream for Watching<A, X>
367where
368 A: Application,
369 X: Clone + Send + 'static,
370{
371 type Item = Result<Entry<X>, Error>;
372
373 fn poll_next(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
374 let watching = self.get_mut();
375
376 if let Some(entry) = watching.pending.pop_front() {
377 return Poll::Ready(Some(Ok(entry)));
378 }
379 if watching.done {
380 return Poll::Ready(None);
381 }
382
383 let mut step = match watching.step.take() {
384 Some(step) => step,
385 None => match watching.parts.take() {
386 Some(parts) => Box::pin(next(parts)),
387 None => {
388 watching.done = true;
389 return Poll::Ready(None);
390 }
391 },
392 };
393
394 match step.as_mut().poll(context) {
395 Poll::Pending => {
396 watching.step = Some(step);
397 Poll::Pending
398 }
399 Poll::Ready((parts, Ok(found))) => {
400 watching.parts = Some(parts);
401 watching.pending.extend(found);
402 match watching.pending.pop_front() {
403 Some(entry) => Poll::Ready(Some(Ok(entry))),
404 None => {
405 watching.done = true;
406 Poll::Ready(None)
407 }
408 }
409 }
410 Poll::Ready((parts, Err(refusal))) => {
411 watching.parts = Some(parts);
412 watching.done = true;
413 Poll::Ready(Some(Err(refusal)))
414 }
415 }
416 }
417}
418
419pub(crate) fn replay<A, W>(
422 catalog: Option<&Dispatch<A, W>>, recorded: Vec<Envelope<W>>, state: &mut At<A::State>, undos: &mut Undos<A>, inverses: Inverting<A>,
423 tail: usize,
424) -> Result<Vec<Arc<Entry<Recorded<A>>>>, DecodeError>
425where
426 A: Application,
427 W: ReplayPayload<A>,
428{
429 let mut redelivered = VecDeque::new();
430
431 for envelope in recorded {
432 let prepared = envelope.payload.prepared();
433 let position = envelope.position;
434 let metadata = envelope.metadata.clone();
435 let link = metadata.link;
436 let principal = metadata.principal.clone();
437 let forward = envelope.payload.forward();
438 let inverse = forward.as_ref().and_then(|change| inverses(change, &state.value));
439 let recovered = W::restore(envelope, catalog, &mut state.value)?;
440
441 if let Some(forward) = &forward {
442 undos.record(position, principal.as_ref(), link, forward, inverse);
443 }
444 if let Some(value) = recovered
445 && tail != 0
446 {
447 let first = metadata.commit.map_or(position, |(first, _)| first);
449 while redelivered.len() >= tail && redelivered.front().is_some_and(|entry: &Arc<Entry<Recorded<A>>>| entry.position < first) {
450 let end = redelivered.front().map(|entry| entry.metadata.commit.map_or(entry.position, |(_, end)| end)).expect("nonempty");
451 while redelivered.front().is_some_and(|entry| entry.position <= end) {
452 redelivered.pop_front();
453 }
454 }
455 redelivered.push_back(Arc::new(Entry { prepared, position, metadata, value }));
456 }
457 state.position = position;
458 }
459
460 Ok(redelivered.into())
461}
462
463pub(crate) fn watching<A, X>(tracked: Arc<TrackedState<A>>, after: Position) -> impl Stream<Item = Result<Entry<X>, Error>>
464where
465 A: Application,
466 X: Clone + Send + 'static,
467{
468 let doorbell = tracked.applied.subscribe();
469
470 Watching { parts: Some(Parts { tracked, frontier: after, doorbell }), step: None, pending: VecDeque::new(), done: false }
471}
472
473async fn next<A, X>(mut parts: Parts<A>) -> (Parts<A>, Result<Vec<Entry<X>>, Error>)
476where
477 A: Application,
478 X: Clone + Send + 'static,
479{
480 loop {
481 if parts.tracked.poisoned() {
482 return (parts, Err(Error::Unavailable));
483 }
484
485 let scanned = {
486 let tail = parts.tracked.tail.read().await;
487 tail.scan::<X>(parts.frontier)
488 };
489
490 match scanned {
491 Err(refusal) => return (parts, Err(refusal)),
492 Ok((found, frontier)) => {
493 parts.frontier = frontier;
494 if !found.is_empty() {
495 return (parts, Ok(found));
496 }
497 }
498 }
499
500 if parts.doorbell.changed().await.is_err() {
501 return (parts, Err(Error::Unavailable));
502 }
503 }
504}
505
506