inc_complete/storage/
mod.rs

1use crate::{Cell, DbHandle};
2
3mod hashmapped;
4mod indexmapped;
5mod macros;
6mod singleton;
7
8pub use hashmapped::HashMapStorage;
9pub use indexmapped::TreeIndexStorage;
10pub use singleton::SingletonStorage;
11
12/// The Storage trait is implemented on a type which can cache all of the computations
13/// used in the program (or a subset of it). These types are typically composed of
14/// several fields with each field implementing `StorageFor<T>` where `T` is one
15/// computation type. Note that each computation type must be unique within a `Storage` type.
16///
17/// This trait is most often automatically implemented by `impl_storage!`, see the documentation
18/// on that macro for usage details.
19///
20/// Note that during serialization, the entire Storage is serialized along with the `Db` object.
21/// To achieve backwards-compatible serialization even when new fields for new computation types
22/// are added, it is recommended to use `#[serde(default)]` on any newly-added fields to still
23/// be able to deserialize from older versions without that field.
24pub trait Storage: Sized {
25    /// For the computation type with the given computation id, return true if the
26    /// output with the given Cell has not yet been set.
27    fn output_is_unset(&self, cell: Cell, computation_id: u32) -> bool;
28
29    /// For the computation type with the given computation id, run the computation
30    /// with the corresponding Cell, returning true if the result changed from its previous value.
31    fn run_computation(db: &DbHandle<Self>, cell: Cell, computation_id: u32) -> bool;
32
33    /// Shrink the storage by removing any data not in use by the given cells
34    fn gc(&mut self, used_cells: &std::collections::HashSet<Cell>);
35
36    /// Return a Debug String representation of the Computation referred to by the given cell.
37    ///
38    /// Used by inc-complete to label components of a cycle when a cycle is detected.
39    fn input_debug_string(&self, cell: Cell) -> String;
40}
41
42/// This trait is implemented by a type storing a single computation type `C`.
43/// Examples include `HashMapStorage<C>`, `SingletonStorage<C>`, and `BTreeMapStorage<C>`.
44///
45/// To implement this efficiently, most types implementing this are two-way maps
46/// from `C` to `Cell` and from `Cell` to `(C, Option<C::Output>)`.
47pub trait StorageFor<C: Computation> {
48    /// Given a computation key, return the cell associated with it, if it exists.
49    fn get_cell_for_computation(&self, key: &C) -> Option<Cell>;
50
51    /// Insert a new Cell with the given computation that has yet to be run
52    fn insert_new_cell(&self, cell: Cell, key: C);
53
54    /// Retrieve the input for this computation, returning `None` if not found.
55    fn try_get_input(&self, cell: Cell) -> Option<C>;
56
57    /// Retrieve the input for this computation.
58    /// The input is expected to already be inserted into this storage.
59    fn get_input(&self, cell: Cell) -> C {
60        self.try_get_input(cell).expect("inc-complete internal error: get_input: expected input to be set")
61    }
62
63    /// Retrieve the output for the given cell, if it exists
64    fn get_output(&self, cell: Cell) -> Option<C::Output>;
65
66    /// `C` has been re-run and has returned the output `new_value`, return `true`
67    /// if `new_value` has changed from its previous value, and cache the new value
68    /// if needed. If `C::ASSUME_CHANGED` is true, skip the comparison and assume the value changed.
69    fn update_output(&self, cell: Cell, new_value: C::Output) -> bool;
70
71    fn gc(&mut self, used_cells: &std::collections::HashSet<Cell>);
72}
73
74pub trait Computation: std::fmt::Debug {
75    type Output;
76    const IS_INPUT: bool;
77    const ASSUME_CHANGED: bool;
78
79    fn computation_id() -> u32;
80}
81
82pub trait Run<Storage>: Computation {
83    fn run(&self, db: &DbHandle<Storage>) -> Self::Output;
84}