Skip to main content

angzarr_client/proto_ext/
books.rs

1//! Book extension traits for EventBook and CommandBook.
2//!
3//! Provides convenience methods for working with pages and sequence numbers.
4
5use crate::proto::{CommandBook, CommandPage, EventBook, EventPage, MergeStrategy, Snapshot};
6
7use super::cover::CoverExt;
8use super::pages::{CommandPageExt, EventPageExt};
9
10/// Extension trait for EventBook proto type (beyond CoverExt).
11///
12/// Provides convenience methods for working with event pages.
13pub trait EventBookExt: CoverExt {
14    /// Get the next sequence number from the pre-computed field.
15    ///
16    /// The framework sets this on load. Returns 0 if not set.
17    fn next_sequence(&self) -> u32;
18
19    /// Check if the event book has no pages.
20    fn is_empty(&self) -> bool;
21
22    /// Get the last event page, if any.
23    fn last_page(&self) -> Option<&EventPage>;
24
25    /// Get the first event page, if any.
26    fn first_page(&self) -> Option<&EventPage>;
27}
28
29/// Compute next sequence number from pages and optional snapshot.
30///
31/// Returns (last page sequence + 1) OR (snapshot sequence + 1) if no pages, OR 0 if neither.
32/// Use this when manually constructing EventBooks or when the framework hasn't set next_sequence.
33pub fn calculate_next_sequence(pages: &[EventPage], snapshot: Option<&Snapshot>) -> u32 {
34    if let Some(last_page) = pages.last() {
35        last_page.sequence_num() + 1
36    } else {
37        snapshot.map(|s| s.sequence + 1).unwrap_or(0)
38    }
39}
40
41/// Calculate and set the next_sequence field on an EventBook.
42pub fn calculate_set_next_seq(book: &mut EventBook) {
43    book.next_sequence = calculate_next_sequence(&book.pages, book.snapshot.as_ref());
44}
45
46impl EventBookExt for EventBook {
47    fn next_sequence(&self) -> u32 {
48        self.next_sequence
49    }
50
51    fn is_empty(&self) -> bool {
52        self.pages.is_empty()
53    }
54
55    fn last_page(&self) -> Option<&EventPage> {
56        self.pages.last()
57    }
58
59    fn first_page(&self) -> Option<&EventPage> {
60        self.pages.first()
61    }
62}
63
64/// Extension trait for CommandBook proto type (beyond CoverExt).
65///
66/// Provides convenience methods for working with command pages.
67pub trait CommandBookExt: CoverExt {
68    /// Get the sequence number from the first command page.
69    fn command_sequence(&self) -> u32;
70
71    /// Get the first command page, if any.
72    fn first_command(&self) -> Option<&CommandPage>;
73
74    /// Get the merge strategy from the first command page.
75    ///
76    /// Returns the MergeStrategy enum value. Defaults to Commutative if no pages.
77    fn merge_strategy(&self) -> MergeStrategy;
78}
79
80impl CommandBookExt for CommandBook {
81    fn command_sequence(&self) -> u32 {
82        self.pages.first().map(|p| p.sequence_num()).unwrap_or(0)
83    }
84
85    fn first_command(&self) -> Option<&CommandPage> {
86        self.pages.first()
87    }
88
89    fn merge_strategy(&self) -> MergeStrategy {
90        self.pages
91            .first()
92            .map(|p| p.merge_strategy())
93            .unwrap_or(MergeStrategy::MergeCommutative)
94    }
95}