1pub mod prelude;
6
7use err_rs::{ErrorLevel, ErrorLevelProvider};
8use log::trace;
9use std::fmt::{Debug, Display};
10use std::marker::PhantomData;
11use tick_id::TickId;
12use tick_queue::{Queue, QueueError};
13
14pub trait SeerCallback<CombinedStepT> {
15 fn on_pre_ticks(&mut self) {}
16
17 fn on_tick(&mut self, step: &CombinedStepT);
18
19 fn on_post_ticks(&mut self) {}
20}
21
22#[derive(Debug)]
23pub enum SeerError {
24 CanNotPushAtMaximumCapacity,
25 QueueError(QueueError),
26}
27
28impl From<QueueError> for SeerError {
29 fn from(error: QueueError) -> Self {
30 Self::QueueError(error)
31 }
32}
33
34impl ErrorLevelProvider for SeerError {
35 fn error_level(&self) -> ErrorLevel {
36 match self {
37 Self::CanNotPushAtMaximumCapacity => ErrorLevel::Warning,
38 Self::QueueError(_) => ErrorLevel::Critical,
39 }
40 }
41}
42
43impl<Callback, CombinedStepT: Clone + Debug + Display> Default for Seer<Callback, CombinedStepT>
44where
45 Callback: SeerCallback<CombinedStepT>,
46{
47 fn default() -> Self {
48 Self::new(Settings::default())
49 }
50}
51
52#[derive(Debug, Copy, Clone)]
53pub struct Settings {
54 pub max_predicted_steps_capacity: usize,
55}
56
57impl Default for Settings {
58 fn default() -> Self {
59 Self {
60 max_predicted_steps_capacity: 14,
61 }
62 }
63}
64
65#[derive(Debug)]
66pub struct Seer<Callback, CombinedStepT>
67where
68 Callback: SeerCallback<CombinedStepT>,
69{
70 predicted_steps: Queue<CombinedStepT>,
71 settings: Settings,
72 phantom: PhantomData<Callback>,
73}
74
75impl<Callback, CombinedStepT> Seer<Callback, CombinedStepT>
76where
77 Callback: SeerCallback<CombinedStepT>,
78 CombinedStepT: Clone + Debug + Display,
79{
80 #[must_use]
81 pub fn new(settings: Settings) -> Self {
82 Self {
83 predicted_steps: Queue::default(),
84 phantom: PhantomData,
85 settings,
86 }
87 }
88
89 #[must_use]
90 pub const fn predicted_steps(&self) -> &Queue<CombinedStepT> {
91 &self.predicted_steps
92 }
93
94 pub fn update(&mut self, callback: &mut Callback) {
95 if self.predicted_steps.is_empty() {
96 return;
97 }
98
99 trace!("pre_ticks");
100 callback.on_pre_ticks();
101
102 trace!("{} predicted steps in queue.", self.predicted_steps.len());
103
104 for combined_step_info in self.predicted_steps.iter() {
105 trace!("tick {}", combined_step_info);
106
107 callback.on_tick(&combined_step_info.item);
108 }
109
110 trace!("post_ticks");
111 callback.on_post_ticks();
112 }
113
114 pub fn received_authoritative(&mut self, tick: TickId) {
115 trace!("received_authoritative discarding predicted steps before {tick}");
116 self.predicted_steps.discard_up_to(tick + 1);
117 trace!("predicted steps remaining {}", self.predicted_steps.len());
118 }
119
120 pub fn push(
124 &mut self,
125 tick_id: TickId,
126 predicted_step: CombinedStepT,
127 ) -> Result<(), SeerError> {
128 if self.predicted_steps.len() >= self.settings.max_predicted_steps_capacity {
129 Err(SeerError::CanNotPushAtMaximumCapacity)?;
130 }
131 self.predicted_steps.push(tick_id, predicted_step)?;
132 Ok(())
133 }
134}