tau_cli_term_raw/
presentation_observation_state.rs1use std::collections::VecDeque;
5use std::time::Instant;
6
7use super::RendererDeliveryId;
8use crate::presentation_mutation_generation::PresentationMutationGeneration;
9
10pub(super) const MAX_PENDING_PRESENTATION_OBSERVATIONS: usize = 64;
12const PRESENTATION_KIND_BITS: usize = u64::BITS as usize;
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub struct PresentationObservationKey(u8);
18
19impl PresentationObservationKey {
20 pub fn new(value: u8) -> Option<Self> {
22 (usize::from(value) < PRESENTATION_KIND_BITS).then_some(Self(value))
23 }
24}
25
26#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
28pub struct PresentationInvalidation(u64);
29
30impl PresentationInvalidation {
31 pub const fn none() -> Self {
33 Self(0)
34 }
35
36 pub const fn with(mut self, key: PresentationObservationKey) -> Self {
38 self.0 |= 1_u64 << key.0;
39 self
40 }
41
42 const fn contains(self, key: PresentationObservationKey) -> bool {
44 self.0 & (1_u64 << key.0) != 0
45 }
46}
47
48#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50pub struct OpaquePresentationFact {
51 label: &'static str,
53 key: PresentationObservationKey,
55 invalidates: PresentationInvalidation,
57}
58
59impl OpaquePresentationFact {
60 pub const fn new(
62 label: &'static str,
63 key: PresentationObservationKey,
64 invalidates: PresentationInvalidation,
65 ) -> Self {
66 Self {
67 label,
68 key,
69 invalidates,
70 }
71 }
72}
73
74pub(super) struct PresentationObservation {
76 pub(super) delivery_id: RendererDeliveryId,
78 pub(super) fact: &'static str,
80 key: PresentationObservationKey,
82 pub(super) generation: PresentationMutationGeneration,
84 pub(super) observed_at: Instant,
86}
87
88pub(super) struct CapturedPresentationObservations {
90 pub(super) facts: Vec<PresentationObservation>,
92 pub(super) omitted: u64,
94 pub(super) generation: PresentationMutationGeneration,
96}
97
98struct OmittedPresentationObservations {
100 key: PresentationObservationKey,
102 count: u64,
104}
105
106impl OmittedPresentationObservations {
107 const fn new(key: PresentationObservationKey) -> Self {
109 Self { key, count: 1 }
110 }
111
112 fn has_key(&self, key: PresentationObservationKey) -> bool {
114 self.key == key
115 }
116
117 const fn is_invalidated_by(&self, invalidates: PresentationInvalidation) -> bool {
119 invalidates.contains(self.key)
120 }
121
122 fn increment(&mut self) {
124 self.count = self.count.saturating_add(1);
125 }
126}
127
128pub(super) struct PresentationObservationState {
130 generation: PresentationMutationGeneration,
132 pending: VecDeque<PresentationObservation>,
134 omitted_by_key: Vec<OmittedPresentationObservations>,
136 omitted_total: u64,
138 #[cfg(test)]
140 pub(super) successful_test_passes:
141 Vec<Vec<(RendererDeliveryId, PresentationMutationGeneration)>>,
142}
143
144impl PresentationObservationState {
145 pub(super) fn new() -> Self {
147 Self {
148 generation: PresentationMutationGeneration::default(),
149 pending: VecDeque::new(),
150 omitted_by_key: Vec::new(),
151 omitted_total: 0,
152 #[cfg(test)]
153 successful_test_passes: Vec::new(),
154 }
155 }
156
157 pub(super) fn is_empty(&self) -> bool {
159 self.pending.is_empty() && self.omitted_total == 0
160 }
161
162 pub(super) fn register(
164 &mut self,
165 delivery_id: RendererDeliveryId,
166 fact: OpaquePresentationFact,
167 observed_at: Instant,
168 ) {
169 self.pending
170 .retain(|pending| !fact.invalidates.contains(pending.key));
171 self.omitted_by_key.retain(|omitted| {
172 if omitted.is_invalidated_by(fact.invalidates) {
173 self.omitted_total = self.omitted_total.saturating_sub(omitted.count);
174 false
175 } else {
176 true
177 }
178 });
179 self.generation.advance();
180 if self.pending.len() == MAX_PENDING_PRESENTATION_OBSERVATIONS {
181 if let Some(omitted) = self
182 .omitted_by_key
183 .iter_mut()
184 .find(|omitted| omitted.has_key(fact.key))
185 {
186 omitted.increment();
187 } else {
188 self.omitted_by_key
189 .push(OmittedPresentationObservations::new(fact.key));
190 }
191 self.omitted_total = self.omitted_total.saturating_add(1);
192 return;
193 }
194 self.pending.push_back(PresentationObservation {
195 delivery_id,
196 fact: fact.label,
197 key: fact.key,
198 generation: self.generation,
199 observed_at,
200 });
201 }
202
203 pub(super) fn capture(&mut self) -> CapturedPresentationObservations {
205 self.omitted_by_key.clear();
206 CapturedPresentationObservations {
207 facts: self.pending.drain(..).collect(),
208 omitted: std::mem::take(&mut self.omitted_total),
209 generation: self.generation,
210 }
211 }
212
213 #[cfg(test)]
215 pub(super) fn record_success_for_test(
216 &mut self,
217 observations: &CapturedPresentationObservations,
218 ) {
219 self.successful_test_passes.push(
220 observations
221 .facts
222 .iter()
223 .map(|fact| (fact.delivery_id, fact.generation))
224 .collect(),
225 );
226 }
227}
228
229#[cfg(test)]
230#[path = "presentation_observation_state_tests.rs"]
231mod presentation_observation_state_tests;