1use serde::de::DeserializeOwned;
2use serde::Serialize;
3
4use super::BackingFile;
5use super::frame::Frame;
6use super::path_builder::QuotickPathBuilder;
7use super::radix_trie::{Trie, TrieCommon};
8use super::Tick;
9
10#[derive(Debug)]
11pub enum EpochError {
12 BackingFileFailure(&'static str),
13 IndexFileFailure,
14 WriteFailure,
15 FrameConflict,
16 FrameTooBig,
17 FrameEmpty,
18}
19
20type FrameIndex<T> = Trie<u64, T>;
21
22pub struct Epoch<T: Tick + Serialize + DeserializeOwned> {
23 frame_index_backing: BackingFile<FrameIndex<T>>,
24
25 pub frame_index: FrameIndex<T>,
26
27 epoch: u64,
28
29 tainted: bool,
30
31 path_builder: QuotickPathBuilder,
32}
33
34impl<T: Tick + Serialize + DeserializeOwned> Epoch<T> {
35 #[inline(always)]
36 pub fn new(
37 epoch: u64,
38 path_builder: QuotickPathBuilder,
39 ) -> Result<Epoch<T>, EpochError> {
40 let mut frame_index_backing =
41 BackingFile::<FrameIndex<T>>::new(
42 path_builder.index_backing_file(epoch),
43 )
44 .or_else(|_|
45 Err(
46 EpochError::BackingFileFailure(
47 "Failed to open frame index backing file.",
48 ),
49 )
50 )?;
51
52 let frame_index =
53 frame_index_backing.try_read()
54 .unwrap_or_else(|_| Trie::new());
55
56 Ok(
57 Epoch {
58 frame_index_backing,
59 frame_index,
60
61 epoch,
62 tainted: false,
63
64 path_builder,
65 },
66 )
67 }
68
69 #[inline(always)]
70 pub fn frames(&mut self) -> impl Iterator<Item=Frame<T>> + '_ {
71 self.frame_index
72 .iter()
73 .map(|(time, item)|
74 Frame::new(
75 *time,
76 item.clone(),
77 ),
78 )
79 }
80
81 #[inline(always)]
82 pub fn epoch(&self) -> u64 {
83 self.epoch
84 }
85
86 #[inline(always)]
87 pub fn insert(
88 &mut self,
89 frame: &Frame<T>,
90 force_overwrite: bool,
91 ) -> Result<(), EpochError> {
92 let time = frame.time();
93
94 if !force_overwrite && self.frame_index.get(&time).is_some() {
95 return Err(EpochError::FrameConflict);
96 }
97
98 self.frame_index
99 .insert(
100 time,
101 frame.tick().clone(),
102 );
103
104 self.tainted = true;
105
106 Ok(())
107 }
108
109 #[inline(always)]
110 pub fn persist(&mut self) {
111 if !self.tainted {
112 return;
113 }
114
115 self.frame_index_backing
116 .write_all(
117 &self.frame_index,
118 );
119
120 self.tainted = false;
121 }
122}
123
124impl<T: Tick + Serialize + DeserializeOwned> Drop for Epoch<T> {
125 #[inline(always)]
126 fn drop(&mut self) {
127 self.persist();
128 }
129}