twine_macros/
lib.rs

1mod time_integrable;
2mod utils;
3
4use proc_macro::TokenStream;
5use syn::parse_macro_input;
6
7/// Implements [`TimeIntegrable`] for structs whose fields all implement it.
8///
9/// When applied to a struct, this macro:
10///
11/// - Generates a time derivative struct named `{StructName}TimeDerivative`,
12///   where each field is a [`TimeDerivative<T>`] corresponding to the original field's type.
13/// - Implements [`TimeIntegrable`] for the struct by calling `.step(...)` on each field,
14///   using that field's own [`TimeIntegrable`] implementation.
15///
16/// ## Restrictions
17///
18/// - The input struct must use named fields (not tuple or unit structs).
19/// - All fields must implement [`TimeIntegrable`].
20///
21/// ## Example
22///
23/// ### Input
24///
25/// ```ignore
26/// #[derive(TimeIntegrable)]
27/// struct StateVariables {
28///     temperature: ThermodynamicTemperature,
29///     pressure: Pressure,
30/// }
31/// ```
32///
33/// ### Expanded
34///
35/// ```ignore
36/// #[derive(Debug, Clone, Copy, PartialEq)]
37/// struct StateVariablesTimeDerivative {
38///     temperature: TimeDerivative<ThermodynamicTemperature>,
39///     pressure: TimeDerivative<Pressure>,
40/// }
41///
42/// impl TimeIntegrable for StateVariables {
43///     type Derivative = StateVariablesTimeDerivative;
44///
45///     fn step(self, derivative: Self::Derivative, dt: Time) -> Self {
46///         Self {
47///             temperature: self.temperature.step(derivative.temperature, dt),
48///             pressure: self.pressure.step(derivative.pressure, dt),
49///         }
50///     }
51/// }
52/// ```
53///
54/// [`TimeIntegrable`]: twine_core::TimeIntegrable
55/// [`TimeDerivative<T>`]: twine_core::TimeDerivative
56#[proc_macro_derive(TimeIntegrable)]
57pub fn derive_time_integrable(input: TokenStream) -> TokenStream {
58    let parsed = parse_macro_input!(input as time_integrable::Parsed);
59    parsed.expand().into()
60}