nimble_seer/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/nimble-rust/nimble
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5pub 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    /// # Errors
121    ///
122    /// `SeerError`
123    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}