liminal_protocol/lifecycle/
observer_progress_projection.rs1use crate::wire::{ConversationId, DeliverySeq};
5
6#[derive(Debug, Eq)]
19pub struct ObserverProgressProjection {
20 conversation_id: ConversationId,
21 new_observer_progress: DeliverySeq,
22 source: Option<crate::lifecycle::checkpoint_codec::ObserverProjectionSource>,
23}
24
25impl PartialEq for ObserverProgressProjection {
26 fn eq(&self, other: &Self) -> bool {
27 self.conversation_id == other.conversation_id
28 && self.new_observer_progress == other.new_observer_progress
29 }
30}
31
32impl ObserverProgressProjection {
33 #[cfg(any(test, feature = "test-support"))]
34 pub(in crate::lifecycle) const fn new(
35 conversation_id: ConversationId,
36 new_observer_progress: DeliverySeq,
37 ) -> Self {
38 Self {
39 conversation_id,
40 new_observer_progress,
41 source: None,
42 }
43 }
44
45 pub(in crate::lifecycle) const fn sourced(
46 conversation_id: ConversationId,
47 new_observer_progress: DeliverySeq,
48 source: crate::lifecycle::checkpoint_codec::ObserverProjectionSource,
49 ) -> Self {
50 Self::with_checkpoint_source(conversation_id, new_observer_progress, Some(source))
51 }
52
53 pub(in crate::lifecycle) const fn with_checkpoint_source(
54 conversation_id: ConversationId,
55 new_observer_progress: DeliverySeq,
56 source: Option<crate::lifecycle::checkpoint_codec::ObserverProjectionSource>,
57 ) -> Self {
58 Self {
59 conversation_id,
60 new_observer_progress,
61 source,
62 }
63 }
64
65 #[doc(hidden)]
70 pub fn encode_checkpoint_source(
71 &self,
72 ) -> Result<alloc::vec::Vec<u8>, crate::lifecycle::OwnerCheckpointRestoreError> {
73 crate::lifecycle::checkpoint_codec::encode_observer_source(
74 self.conversation_id,
75 self.new_observer_progress,
76 self.source
77 .ok_or(crate::lifecycle::OwnerCheckpointRestoreError::Field(
78 "observer_projection.native_source",
79 ))?,
80 )
81 }
82
83 #[doc(hidden)]
85 #[must_use]
86 pub const fn checkpoint_source_participant_id(&self) -> Option<crate::wire::ParticipantId> {
87 match self.source {
88 Some(source) => Some(source.participant_id()),
89 None => None,
90 }
91 }
92
93 #[doc(hidden)]
95 #[must_use]
96 pub const fn checkpoint_source_binding_epoch(&self) -> Option<crate::wire::BindingEpoch> {
97 match self.source {
98 Some(source) => source.binding_epoch(),
99 None => None,
100 }
101 }
102
103 #[doc(hidden)]
105 #[must_use]
106 pub const fn checkpoint_source_kind(
107 &self,
108 ) -> Option<crate::lifecycle::checkpoint_codec::ObserverProjectionCheckpointKind> {
109 match self.source {
110 Some(source) => Some(source.kind()),
111 None => None,
112 }
113 }
114
115 #[cfg(any(test, feature = "test-support"))]
120 #[must_use]
121 pub const fn for_test(
122 conversation_id: ConversationId,
123 new_observer_progress: DeliverySeq,
124 ) -> Self {
125 Self::new(conversation_id, new_observer_progress)
126 }
127
128 #[must_use]
130 pub const fn conversation_id(&self) -> ConversationId {
131 self.conversation_id
132 }
133
134 #[must_use]
136 pub const fn new_observer_progress(&self) -> DeliverySeq {
137 self.new_observer_progress
138 }
139}
140
141impl ObserverProgressProjection {
142 #[must_use]
144 pub fn encode_checkpoint(&self) -> [u8; 16] {
145 let mut body = [0; 16];
146 body[..8].copy_from_slice(&self.conversation_id.to_be_bytes());
147 body[8..].copy_from_slice(&self.new_observer_progress.to_be_bytes());
148 body
149 }
150
151 pub fn restore_checkpoint(
159 body: &[u8],
160 source: Self,
161 ) -> Result<Self, crate::lifecycle::OwnerCheckpointRestoreError> {
162 if body != source.encode_checkpoint() {
163 return Err(crate::lifecycle::OwnerCheckpointRestoreError::Field(
164 "observer_projection.source",
165 ));
166 }
167 Ok(source)
168 }
169}