cellular_raza_core_proc_macro/
lib.rs

1#![deny(missing_docs)]
2//! This crate provides powerful macros to derive traits from the core crate.
3//! It also provides macros to automatically construct AuxStorage structs
4//! used to store intermediate data for running update steps and Communicator
5//! struct to send messages between threads running the simulation.
6//!
7//! All macros are documented in the core crate unless their functionality can be
8//! displayed without any additional dependencies.
9
10#[macro_use]
11mod kwargs;
12
13mod aux_storage;
14mod communicator;
15mod from_map;
16mod run_sim;
17mod simulation_aspects;
18mod testing;
19
20#[allow(missing_docs)]
21#[proc_macro_derive(
22    AuxStorage,
23    attributes(
24        AuxStorageCorePath,
25        UpdateCycle,
26        UpdateMechanics,
27        UpdateNeighborSensing,
28        UpdateReactions,
29        UpdateReactionsContact,
30    )
31)]
32pub fn _aux_storage(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
33    aux_storage::derive_aux_storage(input)
34}
35
36#[allow(missing_docs)]
37#[proc_macro]
38pub fn build_aux_storage(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
39    let kwargs = syn::parse_macro_input!(input as aux_storage::KwargsAuxStorageParsed);
40    let kwargs = aux_storage::KwargsAuxStorage::from(kwargs);
41    aux_storage::construct_aux_storage(kwargs)
42}
43
44#[allow(missing_docs)]
45#[proc_macro]
46pub fn aux_storage_constructor(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
47    let kwargs = syn::parse_macro_input!(input as aux_storage::KwargsAuxStorageParsed);
48    let kwargs = aux_storage::KwargsAuxStorage::from(kwargs);
49    let res = aux_storage::default_aux_storage_initializer(&kwargs);
50    quote::quote!(#res).into()
51}
52
53#[allow(missing_docs)]
54#[proc_macro_derive(Communicator, attributes(CommunicatorCorePath, Comm))]
55pub fn _communicator(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
56    communicator::derive_communicator(input)
57}
58
59#[allow(missing_docs)]
60#[proc_macro]
61pub fn build_communicator(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
62    communicator::construct_communicator(input)
63}
64
65/// Inserts as many blanks as generics were used to create the communicator struct by
66/// [build_communicator!].
67#[proc_macro]
68pub fn communicator_generics_placeholders(
69    input: proc_macro::TokenStream,
70) -> proc_macro::TokenStream {
71    communicator::communicator_generics_placeholders(input)
72}
73
74#[allow(missing_docs)]
75#[proc_macro_derive(FromMap, attributes(FromMapCorePath, FromMapIndex))]
76pub fn from_map(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
77    from_map::derive_from_map(input)
78}
79
80#[proc_macro]
81/// Run a particularly structured test multiple times for combinations of aspects
82///
83/// The tests which we would like to run are macros that will
84/// be given as one argument to this `proc_macro`.
85/// These tests need to adhere to a strict format.
86/// ```
87/// macro_rules! some_test(
88///     (
89///         name:$test_name:ident,
90///         aspects:[$($asp:ident),*]
91///     ) => {
92///         // Any code can be run here.
93///         // For example, we can create a docstring test by using
94///
95///         /// ```
96///         /// assert_eq!(0_usize, 10_usize - 10_usize);
97///         $(#[doc = concat!("println!(\"", stringify!($asp), "\")")])*
98///         /// ```
99///         fn $test_name () {}
100///     }
101/// );
102///
103/// // This is how you would call the test by hand
104///
105/// some_test!(
106///     name:my_test_name,
107///     aspects: [Mechanics, Interaction]
108/// );
109/// ```
110///
111/// In the next step, we can use `run_test_for_aspects` to run this automatically generated
112/// docstring test for every combination of aspects that we specify.
113///
114/// ```
115/// # macro_rules! some_test(
116/// #     (
117/// #         name:$test_name:ident,
118/// #         aspects:[$($asp:ident),*]
119/// #     ) => {
120/// #         // Any code can be run here.
121/// #         // For example, we can create a docstring test by using
122/// #
123/// #         /// ```
124/// #         /// assert_eq!(0_usize, 10_usize - 10_usize);
125/// #         $(#[doc = concat!("println!(\"", stringify!($asp), "\")")])*
126/// #         /// ```
127/// #         fn $test_name () {}
128/// #     }
129/// # );
130/// # use cellular_raza_core_proc_macro::run_test_for_aspects;
131/// run_test_for_aspects!(
132///     test: some_test,
133///     aspects: [Mechanics, Interaction]
134/// );
135/// ```
136/// This will have generated the following code:
137/// ```
138/// # macro_rules! some_test(
139/// #     (
140/// #         name:$test_name:ident,
141/// #         aspects:[$($asp:ident),*]
142/// #     ) => {
143/// #         // Any code can be run here.
144/// #         // For example, we can create a docstring test by using
145/// #
146/// #         /// ```
147/// #         /// assert_eq!(0_usize, 10_usize - 10_usize);
148/// #         $(#[doc = concat!("println!(\"", stringify!($asp), "\")")])*
149/// #         /// ```
150/// #         fn $test_name () {}
151/// #     }
152/// # );
153/// some_test!(
154///     name:mechanics,
155///     aspects: [Mechanics]
156/// );
157/// some_test!(
158///     name:interaction,
159///     aspects: [Interaction]
160/// );
161/// some_test!(
162///     name:mechanics_interaction,
163///     aspects: [Mechanics, Interaction]
164/// );
165/// some_test!(
166///     name:interaction_mechanics,
167///     aspects: [Interaction, Mechanics]
168/// );
169/// ```
170///
171/// # Minimum Combinations
172/// It is possible to specify a minimum number of combinations to test.
173/// This means if we specify N aspects but only want to test combinations of M (where M<N)
174/// different aspects, we can set the `min_combinations` variable of this macro.
175///
176/// ```
177/// # macro_rules! some_test(
178/// #     (
179/// #         name:$test_name:ident,
180/// #         aspects:[$($asp:ident),*]
181/// #     ) => {
182/// #         // Any code can be run here.
183/// #         // For example, we can create a docstring test by using
184/// #
185/// #         /// ```
186/// #         /// assert_eq!(0_usize, 10_usize - 10_usize);
187/// #         $(#[doc = concat!("println!(\"", stringify!($asp), "\")")])*
188/// #         /// ```
189/// #         fn $test_name () {}
190/// #     }
191/// # );
192/// # use cellular_raza_core_proc_macro::run_test_for_aspects;
193/// run_test_for_aspects!(
194///     test: some_test,
195///     aspects: [Mechanics, Interaction, Cycle, Reactions],
196///     min_combinations: 3,
197/// );
198/// ```
199///
200/// # Unsorted Combinations
201/// By default all generated combinations of simulation aspects are sorted and will thus not
202/// produce different tests when being reordered.
203/// This means we assume that `aspects: [Mechanics, Interaction]` is identical to `aspects:
204/// [Interaction, Mechanics]`.
205/// In the case where we also want to test the unsorted cases, we can specify the `sorted` keyword.
206///
207/// ```
208/// # macro_rules! some_test(
209/// #     (
210/// #         name:$test_name:ident,
211/// #         aspects:[$($asp:ident),*]
212/// #     ) => {
213/// #         // Any code can be run here.
214/// #         // For example, we can create a docstring test by using
215/// #
216/// #         /// ```
217/// #         /// assert_eq!(0_usize, 10_usize - 10_usize);
218/// #         $(#[doc = concat!("println!(\"", stringify!($asp), "\")")])*
219/// #         /// ```
220/// #         fn $test_name () {}
221/// #     }
222/// # );
223/// # use cellular_raza_core_proc_macro::run_test_for_aspects;
224/// run_test_for_aspects!(
225///     test: some_test,
226///     aspects: [Mechanics, Interaction],
227///     sorted: false,
228/// );
229/// ```
230pub fn run_test_for_aspects(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
231    testing::run_test_for_aspects(input)
232}
233
234#[allow(missing_docs)]
235#[proc_macro]
236pub fn run_simulation(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
237    let kwargs = syn::parse_macro_input!(input as run_sim::KwargsSimParsed);
238    let kwargs = run_sim::KwargsSim::from(kwargs);
239    run_sim::run_simulation(kwargs).into()
240}
241
242/// Prepares communicator and auxiliary storage types with [build_communicator!] and
243/// [build_aux_storage!].
244#[proc_macro]
245pub fn prepare_types(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
246    let kwargs = syn::parse_macro_input!(input as run_sim::KwargsPrepareTypesParsed);
247    let kwargs = run_sim::KwargsPrepareTypes::from(kwargs);
248    run_sim::prepare_types(kwargs).into()
249}
250
251/// Checks if defined types and concepts are compatible before actually executing the simulation.
252///
253/// This macro only serves the purpose for easy-to-read compiler errors.
254/// It has no runtime-overhead since it will be fully optimized away.
255#[proc_macro]
256pub fn test_compatibility(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
257    let kwargs = syn::parse_macro_input!(input as run_sim::KwargsCompatibilityParsed);
258    let kwargs = run_sim::KwargsCompatibility::from(kwargs);
259    run_sim::test_compatibility(kwargs).into()
260}
261
262#[allow(missing_docs)]
263#[proc_macro]
264pub fn run_main(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
265    let kwargs = syn::parse_macro_input!(input as run_sim::KwargsMainParsed);
266    let kwargs = run_sim::KwargsMain::from(kwargs);
267    run_sim::run_main(kwargs).into()
268}