#[macro_export]
macro_rules! define_intermediate {
( $id:tt, $type_name:ident -> $output_type:ty, $( $storage_type:ty )|+, $run_function:expr) => {
define_intermediate!(@ $id, $type_name -> $output_type, false, $( $storage_type )|+, $run_function);
};
( $id:tt, assume_changed $type_name:ident -> $output_type:ty, $( $storage_type:ty )|+, $run_function:expr) => {
define_intermediate!(@ $id, $type_name -> $output_type, true, $( $storage_type )|+, $run_function);
};
(@ $id:tt, $type_name:ident -> $output_type:ty, $assume_changed:expr, $( $storage_type:ty )|+, $run_function:expr) => {
impl $crate::Computation for $type_name {
type Output = $output_type;
const IS_INPUT: bool = false;
const ASSUME_CHANGED: bool = $assume_changed;
fn computation_id() -> u32 {
$id
}
}
impl $type_name {
#[allow(unused)]
pub fn get(self, db: &impl $crate::DbGet<$type_name>) -> $output_type {
db.get(self)
}
}
$(
impl $crate::Run<$storage_type> for $type_name {
fn run(&self, db: &$crate::DbHandle<$storage_type>) -> $output_type {
let f: fn(&Self, &$crate::DbHandle<$storage_type>) -> $output_type =
$run_function;
f(self, db)
}
}
)+
};
}
#[macro_export]
macro_rules! define_input {
( $id:tt, $type_name:ident -> $output_type:ty, $( $storage_type:ty )|+ ) => {
define_input!(@ $id, $type_name -> $output_type, false, $( $storage_type )|+);
};
( $id:tt, assume_changed $type_name:ident -> $output_type:ty, $( $storage_type:ty )|+ ) => {
define_input!(@ $id, $type_name -> $output_type, true, $( $storage_type )|+);
};
(@ $id:tt, $type_name:ident -> $output_type:ty, $assume_changed:expr, $( $storage_type:ty )|+ ) => {
impl $crate::Computation for $type_name {
type Output = $output_type;
const IS_INPUT: bool = true;
const ASSUME_CHANGED: bool = $assume_changed;
fn computation_id() -> u32 {
$id
}
}
impl $type_name {
#[allow(unused)]
pub fn get(self, db: &impl $crate::DbGet<$type_name>) -> $output_type {
db.get(self)
}
#[allow(unused)]
pub fn set<S>(self, db: &mut $crate::Db<S>, value: $output_type) where S: $crate::Storage + $crate::StorageFor<$type_name> {
db.update_input(self, value);
}
}
$(
impl $crate::Run<$storage_type> for $type_name {
fn run(&self, _: &$crate::DbHandle<$storage_type>) -> $output_type {
panic!("Attempted to call `run` function on input {}, did you forget to call `update_input`?",
stringify!($type_name))
}
}
)+
};
}
#[macro_export]
macro_rules! impl_storage {
($typ:ty, $( $field:ident : $computation_type:ty, )* $(@accumulators { $($acc_field:ident : $acc_type:ty, )* })? ) => {
impl $crate::Storage for $typ {
fn output_is_unset(&self, cell: $crate::Cell, computation_id: u32) -> bool {
use $crate::StorageFor;
match computation_id {
$(
x if x == <$computation_type as $crate::Computation>::computation_id() => {
self.$field.get_output(cell).is_none()
},
)*
id => panic!("Unknown computation id: {id}"),
}
}
$crate::run_computation!( $($field: $computation_type),* );
fn gc(&mut self, used_cells: &std::collections::HashSet<$crate::Cell>) {
use $crate::StorageFor;
$(
self.$field.gc(&used_cells);
)*
}
fn input_debug_string(&self, db: &$crate::Db<Self>, cell: $crate::Cell) -> String {
use $crate::StorageFor;
$(
if let Some(input) = self.$field.try_get_input(cell) {
return format!("{:?}", $crate::debug_with_db(&input, db));
}
)*
panic!("inc-complete internal error: input_debug_string: {cell:?} not found")
}
fn clear_accumulated_for_cell(&self, _cell: $crate::Cell) {
$( $(
self.$acc_field.clear(_cell);
)* )?
}
}
$(
impl $crate::StorageFor<$computation_type> for $typ {
fn get_cell_for_computation(&self, key: &$computation_type) -> Option<$crate::Cell> {
self.$field.get_cell_for_computation(key)
}
fn insert_new_cell(&self, cell: $crate::Cell, key: $computation_type) {
self.$field.insert_new_cell(cell, key)
}
fn try_get_input(&self, cell: $crate::Cell) -> Option<$computation_type> {
self.$field.try_get_input(cell)
}
fn get_output(&self, cell: $crate::Cell) -> Option<<$computation_type as $crate::Computation>::Output> {
self.$field.get_output(cell)
}
fn update_output(&self, cell: $crate::Cell, new_value: <$computation_type as $crate::Computation>::Output) -> bool {
self.$field.update_output(cell, new_value)
}
fn gc(&mut self, used_cells: &std::collections::HashSet<$crate::Cell>) {
self.$field.gc(used_cells);
}
})*
$($(
impl $crate::accumulate::Accumulate<$acc_type> for $typ {
fn accumulate(&self, cell: $crate::Cell, item: $acc_type) {
self.$acc_field.accumulate(cell, item)
}
fn get_accumulated<Items>(&self, cell: $crate::Cell) -> Items
where Items: FromIterator<$acc_type>
{
self.$acc_field.get_accumulated(cell)
}
}
)*)?
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! run_computation {
( $($field:ident: $computation_type:ty),* ) => {
fn run_computation(db: &$crate::DbHandle<Self>, cell: $crate::Cell, computation_id: u32) -> bool {
use $crate::{ StorageFor, Run };
match computation_id {
$(
x if x == <$computation_type as $crate::Computation>::computation_id() => {
let new_value = db.storage().$field.get_input(cell).run(db);
db.storage().$field.update_output(cell, new_value)
}
)*
id => panic!("Unknown computation id: {id}"),
}
}
}
}