1use crate::{Cell, Db, DbHandle};
2use std::any::{Any, TypeId};
3
4mod tuple_impls;
5mod input;
6mod intermediate;
7mod singleton;
8mod hashmapped;
9mod btreemapped;
10
11#[macro_use]
12mod macros;
13
14pub use input::{ Input, OutputTypeForInput };
15pub use intermediate::{ Intermediate, Run };
16pub use singleton::SingletonStorage;
17pub use hashmapped::HashMapStorage;
18pub use btreemapped::BTreeMapStorage;
19
20pub trait Computation: 'static + Sized + Clone {
21 type Storage;
22 type Output: Eq;
23
24 fn run(&self, handle: &mut DbHandle<impl Computation>) -> Self::Output;
25
26 fn input_to_cell(input: &Self, storage: &Self::Storage) -> Option<Cell>;
27 fn insert_new_cell(cell: Cell, function: Self, storage: &mut Self::Storage);
28
29 fn get_function_and_output(
30 cell: Cell,
31 storage: &Self::Storage,
32 ) -> (&Self, Option<&Self::Output>);
33 fn set_output(cell: Cell, output: Self::Output, storage: &mut Self::Storage);
34
35 #[inline(always)]
39 fn computation_id_of<T: Computation>() -> u32 {
40 0
41 }
42
43 fn get_storage<Concrete: Computation + 'static>(
44 computation_id: u32,
45 container: &Self::Storage,
46 ) -> &Concrete::Storage {
47 assert_eq!(computation_id, 0, "Type dispatch failed for get_storage");
48
49 assert_eq!(
50 TypeId::of::<Concrete::Storage>(),
51 TypeId::of::<Self::Storage>(),
52 "Type dispatch failed for get_storage storage type:\n {}\n != {}",
53 std::any::type_name::<Concrete::Storage>(),
54 std::any::type_name::<Self::Storage>(),
55 );
56
57 unsafe { std::mem::transmute(container) }
59 }
60
61 fn get_storage_mut<Concrete: Computation + 'static>(
62 computation_id: u32,
63 container: &mut Self::Storage,
64 ) -> &mut Concrete::Storage {
65 assert_eq!(
66 computation_id, 0,
67 "Type dispatch failed for get_storage_mut container"
68 );
69
70 assert_eq!(
71 TypeId::of::<Concrete::Storage>(),
72 TypeId::of::<Self::Storage>(),
73 "Type dispatch failed for get_storage_mut container type"
74 );
75
76 unsafe { std::mem::transmute(container) }
78 }
79
80 fn output_is_unset<FullComputation: Computation>(
82 cell: Cell,
83 computation_id: u32,
84 original_computation_id: u32,
85 db: &Db<FullComputation>,
86 ) -> bool {
87 assert_eq!(
88 computation_id, 0,
89 "Type dispatch failed for output_is_unset"
90 );
91
92 let container = FullComputation::get_storage::<Self>(original_computation_id, db.storage());
93 let unset = Self::get_function_and_output(cell, container).1.is_none();
94 println!("{} output is unset: {unset}", std::any::type_name::<Self>());
95 unset
96 }
97
98 fn dispatch_run<FullComputation: Computation>(
103 cell: Cell,
104 computation_id: u32,
105 original_computation_id: u32,
106 db: &mut Db<FullComputation>,
107 ) -> bool
108 where
109 Self: Clone,
110 Self::Output: Eq,
111 {
112 assert_eq!(computation_id, 0, "Type dispatch failed for dispatch_run");
113
114 let container =
115 FullComputation::get_storage_mut::<Self>(original_computation_id, db.storage_mut());
116 let function = Self::get_function_and_output(cell, container).0.clone();
117 let output = function.run(&mut db.handle(cell));
118 FullComputation::dispatch_update_output::<Self, FullComputation>(
119 cell,
120 original_computation_id,
121 original_computation_id,
122 output,
123 db,
124 )
125 }
126
127 fn dispatch_update_output<Concrete, FullComputation>(
134 cell: Cell,
135 computation_id: u32,
136 original_computation_id: u32,
137 output: Concrete::Output,
138 db: &mut Db<FullComputation>,
139 ) -> bool
140 where
141 Concrete: Computation,
142 FullComputation: Computation,
143 Self::Output: Eq,
144 {
145 assert_eq!(
146 computation_id, 0,
147 "Type dispatch failed for dispatch_update_output"
148 );
149 assert_eq!(
150 TypeId::of::<Concrete::Output>(),
151 TypeId::of::<Self::Output>(),
152 "Type dispatch failed for dispatch_update_output"
153 );
154
155 let output2: Self::Output = unsafe { std::mem::transmute_copy(&output) };
158 std::mem::forget(output);
159
160 let container =
161 FullComputation::get_storage_mut::<Self>(original_computation_id, db.storage_mut());
162
163 let (_, previous_value) = Self::get_function_and_output(cell, container);
164 let changed = previous_value.map_or(true, |previous| output2 != *previous);
165
166 if changed {
167 Self::set_output(cell, output2, container);
168 }
169
170 changed
171 }
172
173 fn dispatch_input_to_cell<Concrete>(input: &Concrete, container: &Self::Storage) -> Option<Cell>
174 where
175 Concrete: 'static + Computation + Any,
176 {
177 assert_eq!(TypeId::of::<Concrete>(), TypeId::of::<Self>());
178 let input = (input as &dyn Any).downcast_ref().expect("T == Self");
179 Self::input_to_cell(input, container)
180 }
181
182 fn dispatch_insert_new_cell<Concrete>(cell: Cell, input: Concrete, storage: &mut Self::Storage)
183 where
184 Concrete: 'static + Computation + Any,
185 Concrete::Storage: 'static,
186 {
187 let input = transmute_copy_checked::<Concrete, Self>(input);
188 Self::insert_new_cell(cell, input, storage)
189 }
190}
191
192fn transmute_copy_checked<A: 'static, B: 'static>(x: A) -> B {
193 assert_eq!(TypeId::of::<A>(), TypeId::of::<B>());
194 let x2: B = unsafe { std::mem::transmute_copy(&x) };
196 std::mem::forget(x);
198 x2
199}