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}