nimble_seer/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/nimble-rust/nimble
 * Licensed under the MIT License. See LICENSE in the project root for license information.
 */
pub mod prelude;

use err_rs::{ErrorLevel, ErrorLevelProvider};
use log::trace;
use std::fmt::{Debug, Display};
use std::marker::PhantomData;
use tick_id::TickId;
use tick_queue::{Queue, QueueError};

pub trait SeerCallback<CombinedStepT> {
    fn on_pre_ticks(&mut self) {}

    fn on_tick(&mut self, step: &CombinedStepT);

    fn on_post_ticks(&mut self) {}
}

#[derive(Debug)]
pub enum SeerError {
    CanNotPushAtMaximumCapacity,
    QueueError(QueueError),
}

impl From<QueueError> for SeerError {
    fn from(error: QueueError) -> Self {
        Self::QueueError(error)
    }
}

impl ErrorLevelProvider for SeerError {
    fn error_level(&self) -> ErrorLevel {
        match self {
            Self::CanNotPushAtMaximumCapacity => ErrorLevel::Warning,
            Self::QueueError(_) => ErrorLevel::Critical,
        }
    }
}

impl<Callback, CombinedStepT: Clone + Debug + Display> Default for Seer<Callback, CombinedStepT>
where
    Callback: SeerCallback<CombinedStepT>,
{
    fn default() -> Self {
        Self::new(Settings::default())
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Settings {
    pub max_predicted_steps_capacity: usize,
}

impl Default for Settings {
    fn default() -> Self {
        Self {
            max_predicted_steps_capacity: 14,
        }
    }
}

#[derive(Debug)]
pub struct Seer<Callback, CombinedStepT>
where
    Callback: SeerCallback<CombinedStepT>,
{
    predicted_steps: Queue<CombinedStepT>,
    settings: Settings,
    phantom: PhantomData<Callback>,
}

impl<Callback, CombinedStepT> Seer<Callback, CombinedStepT>
where
    Callback: SeerCallback<CombinedStepT>,
    CombinedStepT: Clone + Debug + Display,
{
    pub fn new(settings: Settings) -> Self {
        Seer {
            predicted_steps: Queue::default(),
            phantom: PhantomData,
            settings,
        }
    }

    pub fn predicted_steps(&self) -> &Queue<CombinedStepT> {
        &self.predicted_steps
    }

    pub fn update(&mut self, callback: &mut Callback) {
        if self.predicted_steps.is_empty() {
            return;
        }

        trace!("pre_ticks");
        callback.on_pre_ticks();

        trace!("{} predicted steps in queue.", self.predicted_steps.len());

        for combined_step_info in self.predicted_steps.iter() {
            trace!("tick {}", combined_step_info);

            callback.on_tick(&combined_step_info.item);
        }

        trace!("post_ticks");
        callback.on_post_ticks();
    }

    pub fn received_authoritative(&mut self, tick: TickId) {
        trace!("received_authoritative discarding predicted steps before {tick}");
        self.predicted_steps.discard_up_to(tick + 1);
        trace!("predicted steps remaining {}", self.predicted_steps.len());
    }

    pub fn push(
        &mut self,
        tick_id: TickId,
        predicted_step: CombinedStepT,
    ) -> Result<(), SeerError> {
        if self.predicted_steps.len() >= self.settings.max_predicted_steps_capacity {
            Err(SeerError::CanNotPushAtMaximumCapacity)?;
        }
        self.predicted_steps.push(tick_id, predicted_step)?;
        Ok(())
    }
}