inc_complete/computation/
mod.rs1use crate::{Cell, Db, DbHandle};
2use std::any::{Any, TypeId};
3
4mod btreemapped;
5mod hashmapped;
6mod input;
7mod intermediate;
8mod singleton;
9mod tuple_impls;
10
11#[macro_use]
12mod macros;
13
14pub use btreemapped::BTreeMapStorage;
15pub use hashmapped::HashMapStorage;
16pub use input::{Input, OutputTypeForInput};
17pub use intermediate::{Intermediate, Run};
18pub use singleton::SingletonStorage;
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 Self::get_function_and_output(cell, container).1.is_none()
94 }
95
96 fn dispatch_run<FullComputation: Computation>(
101 cell: Cell,
102 computation_id: u32,
103 original_computation_id: u32,
104 db: &mut Db<FullComputation>,
105 ) -> bool
106 where
107 Self: Clone,
108 Self::Output: Eq,
109 {
110 assert_eq!(computation_id, 0, "Type dispatch failed for dispatch_run");
111
112 let container =
113 FullComputation::get_storage_mut::<Self>(original_computation_id, db.storage_mut());
114 let function = Self::get_function_and_output(cell, container).0.clone();
115 let output = function.run(&mut db.handle(cell));
116 FullComputation::dispatch_update_output::<Self, FullComputation>(
117 cell,
118 original_computation_id,
119 original_computation_id,
120 output,
121 db,
122 )
123 }
124
125 fn dispatch_update_output<Concrete, FullComputation>(
132 cell: Cell,
133 computation_id: u32,
134 original_computation_id: u32,
135 output: Concrete::Output,
136 db: &mut Db<FullComputation>,
137 ) -> bool
138 where
139 Concrete: Computation,
140 FullComputation: Computation,
141 Self::Output: Eq,
142 {
143 assert_eq!(
144 computation_id, 0,
145 "Type dispatch failed for dispatch_update_output"
146 );
147 assert_eq!(
148 TypeId::of::<Concrete::Output>(),
149 TypeId::of::<Self::Output>(),
150 "Type dispatch failed for dispatch_update_output"
151 );
152
153 let output2: Self::Output = unsafe { std::mem::transmute_copy(&output) };
156 std::mem::forget(output);
157
158 let container =
159 FullComputation::get_storage_mut::<Self>(original_computation_id, db.storage_mut());
160
161 let (_, previous_value) = Self::get_function_and_output(cell, container);
162 let changed = previous_value.map_or(true, |previous| output2 != *previous);
163
164 if changed {
165 Self::set_output(cell, output2, container);
166 }
167
168 changed
169 }
170
171 fn dispatch_input_to_cell<Concrete>(input: &Concrete, container: &Self::Storage) -> Option<Cell>
172 where
173 Concrete: 'static + Computation + Any,
174 {
175 assert_eq!(TypeId::of::<Concrete>(), TypeId::of::<Self>());
176 let input = (input as &dyn Any).downcast_ref().expect("T == Self");
177 Self::input_to_cell(input, container)
178 }
179
180 fn dispatch_insert_new_cell<Concrete>(cell: Cell, input: Concrete, storage: &mut Self::Storage)
181 where
182 Concrete: 'static + Computation + Any,
183 Concrete::Storage: 'static,
184 {
185 let input = transmute_copy_checked::<Concrete, Self>(input);
186 Self::insert_new_cell(cell, input, storage)
187 }
188}
189
190fn transmute_copy_checked<A: 'static, B: 'static>(x: A) -> B {
191 assert_eq!(TypeId::of::<A>(), TypeId::of::<B>());
192 let x2: B = unsafe { std::mem::transmute_copy(&x) };
194 std::mem::forget(x);
196 x2
197}