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 println!("{} is stale", std::any::type_name::<Concrete>());
41 return true;
42 };
43 let r = self.is_stale_cell(cell);
44 println!("{} is stale: {r}", std::any::type_name::<Concrete>());
45 r
46 }
47
48 pub fn is_stale_cell(&self, cell: Cell) -> bool {
51 let computation_id = self.cells[cell.index()].computation_id;
52 if C::output_is_unset::<C>(cell, computation_id, computation_id, self) {
53 println!("output {} is unset", computation_id);
54 return true;
55 }
56
57 let neighbors = self.cells.neighbors(cell.index()).collect::<Vec<_>>();
58
59 neighbors.into_iter().any(|dependency_id| {
61 let dependency = &self.cells[dependency_id];
62 let cell = &self.cells[cell.index()];
63
64 dependency.last_verified_version != self.version
65 || dependency.last_updated_version > cell.last_verified_version
66 })
67 }
68
69 pub fn get_cell<ConcreteC: Computation>(&self, input: &ConcreteC) -> Option<Cell> {
73 C::dispatch_input_to_cell(input, &self.storage)
74 }
75
76 pub fn get_or_insert_cell<ConcreteC>(&mut self, input: ConcreteC) -> Cell
77 where
78 ConcreteC: Computation,
79 {
80 if let Some(cell) = C::dispatch_input_to_cell(&input, &self.storage) {
81 cell
82 } else {
83 let computation_id = C::computation_id_of::<ConcreteC>();
84
85 let new_id = self.cells.add_node(CellData::new(computation_id));
86 let cell = Cell::new(new_id);
87 C::dispatch_insert_new_cell(cell, input, &mut self.storage);
88 cell
89 }
90 }
91
92 pub fn update_input<ConcreteC: Computation>(
97 &mut self,
98 input: ConcreteC,
99 new_value: ConcreteC::Output,
100 ) where
101 ConcreteC: std::fmt::Debug,
102 C::Output: Eq,
103 {
104 let debug = format!("{input:?}");
105 let cell_id = self.get_or_insert_cell(input);
106 debug_assert!(
107 self.is_input(cell_id),
108 "`{debug:?}` is not an input - inputs must have 0 dependencies",
109 );
110
111 let cell = &self.cells[cell_id.index()];
113 let computation_id = cell.computation_id;
114
115 let changed = C::dispatch_update_output::<ConcreteC, C>(
116 cell_id,
117 computation_id,
118 computation_id,
119 new_value,
120 self,
121 );
122 let cell = &mut self.cells[cell_id.index()];
123
124 if changed {
125 self.version += 1;
126 cell.last_updated_version = self.version;
127 cell.last_verified_version = self.version;
128 } else {
129 cell.last_verified_version = self.version;
130 }
131 }
132
133 fn is_input(&self, cell: Cell) -> bool {
134 self.cells.neighbors(cell.index()).count() == 0
135 }
136
137 pub(crate) fn handle(&mut self, cell: Cell) -> DbHandle<C> {
138 DbHandle::new(self, cell)
139 }
140
141 pub fn storage(&self) -> &C::Storage {
142 &self.storage
143 }
144
145 pub fn storage_mut(&mut self) -> &mut C::Storage {
146 &mut self.storage
147 }
148
149 #[cfg(test)]
150 pub(crate) fn unwrap_cell_value<Concrete: Computation>(&self, input: &Concrete) -> &CellData
151 where
152 Concrete: std::fmt::Debug,
153 {
154 let cell = self
155 .get_cell(input)
156 .unwrap_or_else(|| panic!("unwrap_cell_value: Expected cell for `{input:?}` to exist"));
157 &self.cells[cell.index()]
158 }
159}
160
161impl<C: Computation + Clone> Db<C>
162where
163 C::Output: Eq,
164{
165 fn run_compute_function(&mut self, cell_id: Cell)
169 where
170 C::Output: Eq,
171 {
172 let cell = &self.cells[cell_id.index()];
173 let computation_id = cell.computation_id;
174
175 let changed = C::dispatch_run::<C>(cell_id, computation_id, computation_id, self);
176
177 let cell = &mut self.cells[cell_id.index()];
178 cell.last_verified_version = self.version;
179
180 if changed {
181 cell.last_updated_version = self.version;
182 }
183 }
184
185 fn update_cell(&mut self, cell_id: Cell) {
188 let cell = &self.cells[cell_id.index()];
189
190 if cell.last_verified_version != self.version {
191 if self.is_stale_cell(cell_id) {
193 self.run_compute_function(cell_id);
194 } else {
195 let cell = &mut self.cells[cell_id.index()];
196 cell.last_verified_version = self.version;
197 }
198 }
199 }
200
201 pub fn get<Concrete: Computation>(&mut self, compute: Concrete) -> &Concrete::Output {
206 let cell_id = self.get_or_insert_cell(compute);
207 self.get_with_cell::<Concrete>(cell_id)
208 }
209
210 pub fn get_with_cell<Concrete: Computation>(&mut self, cell_id: Cell) -> &Concrete::Output {
215 self.update_cell(cell_id);
216
217 let computation_id = self.cells[cell_id.index()].computation_id;
218 println!("get_with_cell get_storage_mut::<{}> with id {}", std::any::type_name::<Concrete>(), computation_id);
219 let container = C::get_storage_mut::<Concrete>(computation_id, self.storage_mut());
220 Concrete::get_function_and_output(cell_id, container)
221 .1
222 .expect("cell result should have been computed already")
223 }
224}