1use crate::cell::CellData;
2use crate::{Cell, Computation};
3use petgraph::graph::DiGraph;
4
5mod handle;
6mod tests;
7
8pub use handle::DbHandle;
9
10const START_VERSION: u32 = 1;
11
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Db<C: Computation> {
14 cells: DiGraph<CellData, ()>,
15 version: u32,
16 storage: C::Storage,
17}
18
19impl<C: Computation> Db<C>
20where
21 C::Storage: Default,
22{
23 pub fn new() -> Self {
24 Self {
25 cells: DiGraph::default(),
26 version: START_VERSION,
27 storage: Default::default(),
28 }
29 }
30}
31
32impl<C: Computation> Db<C> {
33 pub fn is_stale<Concrete: Computation>(&self, input: &Concrete) -> bool {
38 let Some(cell) = self.get_cell(input) else {
40 return true;
41 };
42 self.is_stale_cell(cell)
43 }
44
45 pub fn is_stale_cell(&self, cell: Cell) -> bool {
48 let computation_id = self.cells[cell.index()].computation_id;
49 if C::output_is_unset::<C>(cell, computation_id, computation_id, self) {
50 return true;
51 }
52
53 let neighbors = self.cells.neighbors(cell.index()).collect::<Vec<_>>();
54
55 neighbors.into_iter().any(|dependency_id| {
57 let dependency = &self.cells[dependency_id];
58 let cell = &self.cells[cell.index()];
59
60 dependency.last_verified_version != self.version
61 || dependency.last_updated_version > cell.last_verified_version
62 })
63 }
64
65 pub fn get_cell<ConcreteC: Computation>(&self, input: &ConcreteC) -> Option<Cell> {
69 C::dispatch_input_to_cell(input, &self.storage)
70 }
71
72 pub fn get_or_insert_cell<ConcreteC>(&mut self, input: ConcreteC) -> Cell
73 where
74 ConcreteC: Computation,
75 {
76 if let Some(cell) = C::dispatch_input_to_cell(&input, &self.storage) {
77 cell
78 } else {
79 let computation_id = C::computation_id_of::<ConcreteC>();
80
81 let new_id = self.cells.add_node(CellData::new(computation_id));
82 let cell = Cell::new(new_id);
83 C::dispatch_insert_new_cell(cell, input, &mut self.storage);
84 cell
85 }
86 }
87
88 pub fn update_input<ConcreteC: Computation>(
93 &mut self,
94 input: ConcreteC,
95 new_value: ConcreteC::Output,
96 ) where
97 ConcreteC: std::fmt::Debug,
98 C::Output: Eq,
99 {
100 let debug = format!("{input:?}");
101 let cell_id = self.get_or_insert_cell(input);
102 debug_assert!(
103 self.is_input(cell_id),
104 "`{debug:?}` is not an input - inputs must have 0 dependencies",
105 );
106
107 let cell = &self.cells[cell_id.index()];
109 let computation_id = cell.computation_id;
110
111 let changed = C::dispatch_update_output::<ConcreteC, C>(
112 cell_id,
113 computation_id,
114 computation_id,
115 new_value,
116 self,
117 );
118 let cell = &mut self.cells[cell_id.index()];
119
120 if changed {
121 self.version += 1;
122 cell.last_updated_version = self.version;
123 cell.last_verified_version = self.version;
124 } else {
125 cell.last_verified_version = self.version;
126 }
127 }
128
129 fn is_input(&self, cell: Cell) -> bool {
130 self.cells.neighbors(cell.index()).count() == 0
131 }
132
133 pub(crate) fn handle(&mut self, cell: Cell) -> DbHandle<C> {
134 DbHandle::new(self, cell)
135 }
136
137 pub fn storage(&self) -> &C::Storage {
138 &self.storage
139 }
140
141 pub fn storage_mut(&mut self) -> &mut C::Storage {
142 &mut self.storage
143 }
144
145 #[cfg(test)]
146 pub(crate) fn unwrap_cell_value<Concrete: Computation>(&self, input: &Concrete) -> &CellData
147 where
148 Concrete: std::fmt::Debug,
149 {
150 let cell = self
151 .get_cell(input)
152 .unwrap_or_else(|| panic!("unwrap_cell_value: Expected cell for `{input:?}` to exist"));
153 &self.cells[cell.index()]
154 }
155}
156
157impl<C: Computation + Clone> Db<C>
158where
159 C::Output: Eq,
160{
161 fn run_compute_function(&mut self, cell_id: Cell)
165 where
166 C::Output: Eq,
167 {
168 let cell = &self.cells[cell_id.index()];
169 let computation_id = cell.computation_id;
170
171 let changed = C::dispatch_run::<C>(cell_id, computation_id, computation_id, self);
172
173 let cell = &mut self.cells[cell_id.index()];
174 cell.last_verified_version = self.version;
175
176 if changed {
177 cell.last_updated_version = self.version;
178 }
179 }
180
181 fn update_cell(&mut self, cell_id: Cell) {
184 let cell = &self.cells[cell_id.index()];
185
186 if cell.last_verified_version != self.version {
187 if self.is_stale_cell(cell_id) {
189 self.run_compute_function(cell_id);
190 } else {
191 let cell = &mut self.cells[cell_id.index()];
192 cell.last_verified_version = self.version;
193 }
194 }
195 }
196
197 pub fn get<Concrete: Computation>(&mut self, compute: Concrete) -> &Concrete::Output {
202 let cell_id = self.get_or_insert_cell(compute);
203 self.get_with_cell::<Concrete>(cell_id)
204 }
205
206 pub fn get_with_cell<Concrete: Computation>(&mut self, cell_id: Cell) -> &Concrete::Output {
211 self.update_cell(cell_id);
212
213 let computation_id = self.cells[cell_id.index()].computation_id;
214 let container = C::get_storage_mut::<Concrete>(computation_id, self.storage_mut());
215 Concrete::get_function_and_output(cell_id, container)
216 .1
217 .expect("cell result should have been computed already")
218 }
219}