1use crate::{Cell, Db, DbHandle};
2use std::{
3 any::{Any, TypeId},
4 collections::HashMap,
5 hash::Hash,
6};
7
8mod tuple_impls;
9
10pub trait Computation: 'static + Sized + Clone {
11 type Storage;
12 type Output: Eq;
13
14 fn run(&self, handle: &mut DbHandle<impl Computation>) -> Self::Output;
15
16 fn input_to_cell(input: &Self, storage: &Self::Storage) -> Option<Cell>;
17 fn insert_new_cell(cell: Cell, function: Self, storage: &mut Self::Storage);
18
19 fn get_function_and_output(
20 cell: Cell,
21 storage: &Self::Storage,
22 ) -> (&Self, Option<&Self::Output>);
23 fn set_output(cell: Cell, output: Self::Output, storage: &mut Self::Storage);
24
25 #[inline(always)]
29 fn computation_id_of<T: Computation>() -> u32 {
30 0
31 }
32
33 fn get_storage<Concrete: Computation + 'static>(
34 computation_id: u32,
35 container: &Self::Storage,
36 ) -> &Concrete::Storage {
37 assert_eq!(computation_id, 0, "Type dispatch failed for get_storage");
38
39 assert_eq!(
40 TypeId::of::<Concrete::Storage>(),
41 TypeId::of::<Self::Storage>(),
42 "Type dispatch failed for get_storage storage type:\n {}\n != {}",
43 std::any::type_name::<Concrete::Storage>(),
44 std::any::type_name::<Self::Storage>(),
45 );
46
47 unsafe { std::mem::transmute(container) }
49 }
50
51 fn get_storage_mut<Concrete: Computation + 'static>(
52 computation_id: u32,
53 container: &mut Self::Storage,
54 ) -> &mut Concrete::Storage {
55 assert_eq!(
56 computation_id, 0,
57 "Type dispatch failed for get_storage_mut container"
58 );
59
60 assert_eq!(
61 TypeId::of::<Concrete::Storage>(),
62 TypeId::of::<Self::Storage>(),
63 "Type dispatch failed for get_storage_mut container type"
64 );
65
66 unsafe { std::mem::transmute(container) }
68 }
69
70 fn output_is_unset<FullComputation: Computation>(
72 cell: Cell,
73 computation_id: u32,
74 original_computation_id: u32,
75 db: &Db<FullComputation>,
76 ) -> bool {
77 assert_eq!(
78 computation_id, 0,
79 "Type dispatch failed for output_is_unset"
80 );
81
82 let container = FullComputation::get_storage::<Self>(original_computation_id, db.storage());
83 let unset = Self::get_function_and_output(cell, container).1.is_none();
84 println!("{} output is unset: {unset}", std::any::type_name::<Self>());
85 unset
86 }
87
88 fn dispatch_run<FullComputation: Computation>(
93 cell: Cell,
94 computation_id: u32,
95 original_computation_id: u32,
96 db: &mut Db<FullComputation>,
97 ) -> bool
98 where
99 Self: Clone,
100 Self::Output: Eq,
101 {
102 assert_eq!(computation_id, 0, "Type dispatch failed for dispatch_run");
103
104 let container =
105 FullComputation::get_storage_mut::<Self>(original_computation_id, db.storage_mut());
106 let function = Self::get_function_and_output(cell, container).0.clone();
107 let output = function.run(&mut db.handle(cell));
108 FullComputation::dispatch_update_output::<Self, FullComputation>(
109 cell,
110 original_computation_id,
111 original_computation_id,
112 output,
113 db,
114 )
115 }
116
117 fn dispatch_update_output<Concrete, FullComputation>(
124 cell: Cell,
125 computation_id: u32,
126 original_computation_id: u32,
127 output: Concrete::Output,
128 db: &mut Db<FullComputation>,
129 ) -> bool
130 where
131 Concrete: Computation,
132 FullComputation: Computation,
133 Self::Output: Eq,
134 {
135 assert_eq!(
136 computation_id, 0,
137 "Type dispatch failed for dispatch_update_output"
138 );
139 assert_eq!(
140 TypeId::of::<Concrete::Output>(),
141 TypeId::of::<Self::Output>(),
142 "Type dispatch failed for dispatch_update_output"
143 );
144
145 let output2: Self::Output = unsafe { std::mem::transmute_copy(&output) };
148 std::mem::forget(output);
149
150 let container =
151 FullComputation::get_storage_mut::<Self>(original_computation_id, db.storage_mut());
152
153 let (_, previous_value) = Self::get_function_and_output(cell, container);
154 let changed = previous_value.map_or(true, |previous| output2 != *previous);
155
156 if changed {
157 Self::set_output(cell, output2, container);
158 }
159
160 changed
161 }
162
163 fn dispatch_input_to_cell<Concrete>(input: &Concrete, container: &Self::Storage) -> Option<Cell>
164 where
165 Concrete: 'static + Computation + Any,
166 {
167 assert_eq!(TypeId::of::<Concrete>(), TypeId::of::<Self>());
168 let input = (input as &dyn Any).downcast_ref().expect("T == Self");
169 Self::input_to_cell(input, container)
170 }
171
172 fn dispatch_insert_new_cell<Concrete>(cell: Cell, input: Concrete, storage: &mut Self::Storage)
173 where
174 Concrete: 'static + Computation + Any,
175 Concrete::Storage: 'static,
176 {
177 let input = transmute_copy_checked::<Concrete, Self>(input);
178 Self::insert_new_cell(cell, input, storage)
179 }
180}
181
182fn transmute_copy_checked<A: 'static, B: 'static>(x: A) -> B {
183 assert_eq!(TypeId::of::<A>(), TypeId::of::<B>());
184 let x2: B = unsafe { std::mem::transmute_copy(&x) };
186 std::mem::forget(x);
188 x2
189}
190
191#[derive(Debug, Clone, PartialEq, Eq, Hash)]
193pub struct Cached<T>(T);
194
195impl<T> Cached<T> {
196 pub const fn new(x: T) -> Self {
197 Self(x)
198 }
199}
200
201pub trait Run {
202 type Output: Eq;
203
204 fn run(&self, handle: &mut DbHandle<impl Computation>) -> Self::Output;
205}
206
207impl<T> Computation for Cached<T>
208where
209 T: 'static + Run + Eq + Hash + Clone,
210{
211 type Output = <T as Run>::Output;
212 type Storage = (
213 HashMap<Self, Cell>,
214 HashMap<Cell, (Self, Option<Self::Output>)>,
215 );
216
217 fn run(&self, handle: &mut DbHandle<impl Computation>) -> Self::Output {
218 self.0.run(handle)
219 }
220
221 fn input_to_cell(input: &Self, (self_to_cell, _): &Self::Storage) -> Option<Cell> {
222 self_to_cell.get(input).copied()
223 }
224
225 fn get_function_and_output(
226 cell: Cell,
227 (_, cell_to_output): &Self::Storage,
228 ) -> (&Self, Option<&Self::Output>) {
229 let (this, output) = &cell_to_output[&cell];
230 (this, output.as_ref())
231 }
232
233 fn set_output(cell: Cell, new_output: Self::Output, (_, cell_to_output): &mut Self::Storage) {
234 cell_to_output.entry(cell).and_modify(|(_, output)| {
235 *output = Some(new_output);
236 });
237 }
238
239 fn insert_new_cell(cell: Cell, function: Self, storage: &mut Self::Storage) {
240 storage.0.insert(function.clone(), cell);
241 storage.1.insert(cell, (function, None));
242 }
243}
244
245#[derive(Debug, Clone)]
253pub struct Input<T>(std::marker::PhantomData<T>);
254
255impl<T> Input<T> {
256 pub const fn new() -> Self {
257 Self(std::marker::PhantomData)
258 }
259}
260
261pub trait OutputTypeForInput: Clone {
262 type Output: Eq;
263}
264
265impl<T: OutputTypeForInput + 'static> Computation for Input<T> {
266 type Output = <T as OutputTypeForInput>::Output;
267 type Storage = (Option<Cell>, Option<Self::Output>);
268
269 fn run(&self, _: &mut DbHandle<impl Computation>) -> Self::Output {
270 panic!(
271 "Input `{}` queried before `db.update_input(..)` called",
272 std::any::type_name::<T>()
273 )
274 }
275
276 fn input_to_cell(_: &Self, storage: &Self::Storage) -> Option<Cell> {
277 storage.0
278 }
279
280 fn get_function_and_output(_: Cell, storage: &Self::Storage) -> (&Self, Option<&Self::Output>) {
281 (&Self(std::marker::PhantomData), storage.1.as_ref())
282 }
283
284 fn set_output(_: Cell, new_output: Self::Output, storage: &mut Self::Storage) {
285 storage.1 = Some(new_output);
286 }
287
288 fn insert_new_cell(cell: Cell, _: Self, storage: &mut Self::Storage) {
289 storage.0 = Some(cell);
290 storage.1 = None;
291 }
292}