libtw2_snapshot/
storage.rs

1use crate::format;
2use crate::snap;
3use crate::snap::Builder;
4use crate::snap::Delta;
5use crate::snap::Snap;
6use std::collections::VecDeque;
7use warn::wrap;
8use warn::Warn;
9
10// TODO: Separate server storage from client storage.
11// TODO: Delete snapshots over time.
12
13#[derive(Clone)]
14struct StoredSnap {
15    snap: Snap,
16    tick: i32,
17}
18
19const MAX_STORED_SNAPSHOT: usize = 100;
20
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct UnknownSnap;
23
24#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct WeirdNegativeDeltaTick;
26
27#[derive(Clone, Debug, Eq, PartialEq)]
28pub enum Error {
29    OldDelta,
30    UnknownSnap,
31    InvalidCrc,
32    Unpack(snap::Error),
33}
34
35impl From<snap::Error> for Error {
36    fn from(err: snap::Error) -> Error {
37        Error::Unpack(err)
38    }
39}
40
41#[derive(Clone, Debug, Eq, PartialEq)]
42pub enum Warning {
43    WeirdNegativeDeltaTick,
44    Unpack(format::Warning),
45}
46
47impl From<format::Warning> for Warning {
48    fn from(w: format::Warning) -> Warning {
49        Warning::Unpack(w)
50    }
51}
52
53#[derive(Clone, Default)]
54pub struct Storage {
55    /// Queue that stores received snaps.
56    ///
57    /// The newest elements are in the front.
58    snaps: VecDeque<StoredSnap>,
59    free: Vec<Snap>,
60    ack_tick: Option<i32>,
61    delta: Delta,
62    delta_tick: Option<i32>,
63}
64
65impl Storage {
66    pub fn new() -> Storage {
67        Default::default()
68    }
69    pub fn reset(&mut self) {
70        let self_free = &mut self.free;
71        // FIXME: Replace with something like `exhaust`.
72        self.snaps.drain(..).map(|s| self_free.push(s.snap)).count();
73        self.ack_tick = None;
74    }
75    pub fn ack_tick(&self) -> Option<i32> {
76        self.ack_tick
77    }
78    pub fn add_delta<W>(
79        &mut self,
80        warn: &mut W,
81        crc: Option<i32>,
82        delta_tick: i32,
83        tick: i32,
84        delta: &Delta,
85    ) -> Result<&Snap, Error>
86    where
87        W: Warn<Warning>,
88    {
89        if self.snaps.front().map(|s| s.tick).unwrap_or(-1) >= tick {
90            return Err(Error::OldDelta);
91        }
92        {
93            let empty = Snap::empty();
94            let delta_snap;
95            if delta_tick >= 0 {
96                if let Some(i) = self.snaps.iter().position(|s| s.tick < delta_tick) {
97                    let self_free = &mut self.free;
98                    // FIXME: Replace with something like `exhaust`.
99                    self.snaps
100                        .drain(i..)
101                        .map(|s| self_free.push(s.snap))
102                        .count();
103                }
104                if let Some(d) = self.snaps.back() {
105                    if d.tick == delta_tick {
106                        delta_snap = &d.snap;
107                    } else {
108                        self.ack_tick = None;
109                        return Err(Error::UnknownSnap);
110                    }
111                } else {
112                    self.ack_tick = None;
113                    return Err(Error::UnknownSnap);
114                }
115            } else {
116                delta_snap = &empty;
117                if delta_tick != -1 {
118                    warn.warn(Warning::WeirdNegativeDeltaTick);
119                }
120            }
121            if self.free.is_empty() {
122                self.free.push(Snap::empty());
123            }
124
125            let new_snap: &mut Snap = self.free.last_mut().unwrap();
126            new_snap.read_with_delta(wrap(warn), delta_snap, delta)?;
127            if crc.map(|crc| crc != new_snap.crc()).unwrap_or(false) {
128                self.ack_tick = None;
129                return Err(Error::InvalidCrc);
130            }
131            self.ack_tick = Some(tick);
132        }
133        self.snaps.push_front(StoredSnap {
134            tick: tick,
135            snap: self.free.pop().unwrap(),
136        });
137        if self.snaps.len() > MAX_STORED_SNAPSHOT {
138            self.free.push(self.snaps.pop_back().unwrap().snap);
139        }
140        Ok(&self.snaps.front().unwrap().snap)
141    }
142    pub fn new_builder(&mut self) -> Builder {
143        self.free.pop().unwrap_or_default().recycle()
144    }
145    pub fn set_delta_tick<W>(&mut self, warn: &mut W, tick: i32) -> Result<(), UnknownSnap>
146    where
147        W: Warn<WeirdNegativeDeltaTick>,
148    {
149        if tick < 0 {
150            if tick != -1 {
151                warn.warn(WeirdNegativeDeltaTick);
152            }
153            self.delta_tick = None;
154            return Ok(());
155        }
156        if let Some(i) = self.snaps.iter().position(|s| s.tick < tick) {
157            let self_free = &mut self.free;
158            // FIXME: Replace with something like `exhaust`.
159            self.snaps
160                .drain(i..)
161                .map(|s| self_free.push(s.snap))
162                .count();
163        }
164        if !self.snaps.back().map(|s| s.tick == tick).unwrap_or(false) {
165            self.delta_tick = None;
166            return Err(UnknownSnap);
167        }
168        self.delta_tick = Some(tick);
169        Ok(())
170    }
171    pub fn delta_tick(&self) -> Option<i32> {
172        self.delta_tick
173    }
174    pub fn add_snap(&mut self, tick: i32, snap: Snap) -> &Delta {
175        self.snaps.push_front(StoredSnap {
176            snap: snap,
177            tick: tick,
178        });
179        let tmp;
180        let delta_snap = if self.delta_tick.is_some() {
181            &self.snaps.back().unwrap().snap
182        } else {
183            tmp = Snap::empty();
184            &tmp
185        };
186        self.delta
187            .create(delta_snap, &self.snaps.front().unwrap().snap);
188        &self.delta
189    }
190}