inc_complete/computation/
macros.rs

1/// Helper macro to define an intermediate computation type. This will
2/// define the type for you along with a `new` method, `Run` impl and
3/// a function wrapper for `db.get(ComputationType::new())`.
4///
5/// Example usage:
6/// ```
7/// # use inc_complete::{ define_intermediate, DbHandle, Computation };
8/// # use std::rc::Rc;
9/// # #[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
10/// # struct Expr;
11/// # #[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
12/// # struct Type;
13/// # #[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
14/// # struct Error;
15/// // Defines the `Parse` type, a `parse` function to get the current parse
16/// // or re-parse if it is out of date, the output type String, and parse_impl
17/// // which actually performs the parse and returns a String.
18/// define_intermediate!(Parse, parse, String, parse_impl);
19///
20/// fn parse_impl(db: &mut DbHandle<impl Computation>) -> String { todo!() }
21///
22/// // You can also specify arguments to the type, prefixing each with `&` if it
23/// // is to be passed by reference to `parse_impl`.
24/// // The output type can also be prefixed with `cloned` if the getter should
25/// // return it cloned instead of a reference
26/// define_intermediate!(TypeCheck { &expr: Rc<Expr> }, type_check, cloned Result<Type, Error>, type_check_impl);
27///
28/// fn type_check_impl(expr: &Rc<Expr>, db: &mut DbHandle<impl Computation>) -> Result<Type, Error> { todo!() }
29/// ```
30#[macro_export]
31macro_rules! define_intermediate {
32    // No `cloned` on output_type
33    ( $type_name:ident $( { $($fields:tt)* } )? ,
34      $get_function_name:ident, $output_type:ty, $impl_function:expr) => {
35        define_intermediate!(@inner $type_name $( { $( $fields )* } )?, $get_function_name, $output_type, $impl_function; (|x|x); &'db);
36    };
37    // `cloned` on output_type
38    ( $type_name:ident $( { $($fields:tt)* } )? ,
39      $get_function_name:ident, cloned $output_type:ty, $impl_function:expr) => {
40        define_intermediate!(@inner $type_name $( { $($fields)* } )?, $get_function_name, $output_type, $impl_function; Clone::clone;);
41    };
42    (@inner $type_name:ident $( { $( $($(@$if_ref:tt)? &)? $field_name:ident : $field_type:ty),* } )? ,
43      $get_function_name:ident, $output_type:ty, $impl_function:expr; $clone_function:expr ; $($output_ref:tt)* ) => {
44
45        $crate::paste::paste! {
46            #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
47            pub(crate) struct [<$type_name Internal>] { $( $( $field_name : $field_type ),* )? }
48
49            pub(crate) type $type_name = $crate::HashMapStorage<$crate::Intermediate<[<$type_name Internal>]>>;
50
51            // Constructor function
52            #[allow(non_snake_case)]
53            #[allow(unused)]
54            pub(crate) fn $type_name($( $( $field_name : $field_type, )* )?) -> $type_name {
55                $crate::HashMapStorage::new($crate::Intermediate::new([<$type_name Internal>] { $( $( $field_name ),* )? }))
56            }
57
58            // Query function with DbHandle
59            #[allow(unused)]
60            pub(crate) fn $get_function_name<'db>($( $( $field_name : $field_type, )* )? db: &'db mut $crate::DbHandle<impl $crate::Computation>) -> $($output_ref)? $output_type {
61                $clone_function(db.get($type_name ( $( $( $field_name ),* )? )))
62            }
63
64            // TODO: Should create a trait to abstract over DbHandle and Db
65            // Query function with Db
66            #[allow(unused)]
67            pub(crate) fn [<$get_function_name _db>]<'db>($( $( $field_name : $field_type, )* )? db: &'db mut $crate::Db<impl $crate::Computation>) -> $($output_ref)? $output_type {
68                $clone_function(db.get($type_name ( $( $( $field_name ),* )? )))
69            }
70
71            impl $crate::Run for [<$type_name Internal>] {
72                type Output = $output_type;
73
74                fn run(&self, handle: &mut $crate::DbHandle<impl $crate::Computation>) -> Self::Output {
75                    $impl_function($( $( $($($if_ref)? & )? self. $field_name, )*)? handle)
76                }
77            }
78        }
79    };
80}
81
82/// Helper macro to define an input type. This will define the type for you along with
83/// an `OutputTypeForInput` impl and a function wrapper for `db.get(ComputationType::new())`.
84///
85/// Note that inputs must be set via `db.update_input(MyInputType, value)` before they are used.
86///
87/// Example usage:
88/// ```
89/// # use inc_complete::define_input;
90/// # #[derive(Debug, PartialEq, Eq, Hash, Clone)]
91/// # struct Expr;
92/// # #[derive(Debug, PartialEq, Eq, Hash, Clone)]
93/// # struct Type;
94/// # #[derive(Debug, PartialEq, Eq, Hash, Clone)]
95/// # struct Error;
96/// // Defines the `SourceFile` type, a `get_source` function to get the current
97/// // source file, and the output type String.
98/// define_input!(SourceFile, get_source, String);
99///
100/// // Inputs can have arguments on their type as well.
101/// // The output type can also be prefixed with `cloned` if the getter should
102/// // return it cloned instead of a reference
103/// define_input!(SourceFile2 { file_id: u32 }, get_source2, cloned String);
104/// ```
105#[macro_export]
106macro_rules! define_input {
107    // No `cloned` on output_type
108    ( $type_name:ident $( { $($fields:tt)* } )? ,
109      $get_function_name:ident, $output_type:ty) => {
110        define_input!($type_name $( { $($fields)* } )?, $get_function_name, $output_type; (|x|x); &'db);
111    };
112    // `cloned` on output_type
113    ( $type_name:ident $( { $($fields:tt)* } )? ,
114      $get_function_name:ident, cloned $output_type:ty) => {
115        define_input!($type_name $( { $($fields)* } )?, $get_function_name, $output_type; Clone::clone;);
116    };
117
118    ( $type_name:ident $( { $( $field_name:ident : $field_type:ty),* } )? ,
119      $get_function_name:ident, $output_type:ty ; $clone_function:expr ; $($output_ref:tt)* ) => {
120
121        $crate::paste::paste! {
122            #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
123            pub(crate) struct [<$type_name Internal>] { $( $( $field_name : $field_type ),* )? }
124
125            pub(crate) type $type_name = $crate::HashMapStorage<$crate::Input<[<$type_name Internal>]>>;
126
127            // Constructor function
128            #[allow(non_snake_case)]
129            #[allow(unused)]
130            pub(crate) fn $type_name($( $( $field_name : $field_type, )* )?) -> $type_name {
131                $crate::HashMapStorage::new($crate::Input::new([<$type_name Internal>] { $( $( $field_name ),* )? }))
132            }
133
134            // Query function with DbHandle
135            #[allow(unused)]
136            pub(crate) fn $get_function_name<'db>($( $( $field_name : $field_type, )* )? db: &'db mut $crate::DbHandle<impl $crate::Computation>) -> $($output_ref)* $output_type {
137                let result = db.get($type_name ($( $( $field_name ),* )? ));
138                $clone_function(result)
139            }
140
141            // TODO: Should create a trait to abstract over DbHandle and Db
142            // Query function with Db
143            #[allow(unused)]
144            pub(crate) fn [<$get_function_name _db>]<'db>($( $( $field_name : $field_type, )* )? db: &'db mut $crate::Db<impl $crate::Computation>) -> $($output_ref)? $output_type {
145                let result = db.get($type_name ($( $( $field_name ),* )? ));
146                $clone_function(result)
147            }
148
149            impl $crate::OutputTypeForInput for [<$type_name Internal>] {
150                type Output = $output_type;
151            }
152        }
153    };
154}