Skip to main content

affn_derive/
lib.rs

1//! # affn-derive
2//!
3//! Derive macros for the `affn` crate, providing `#[derive(ReferenceFrame)]`
4//! and `#[derive(ReferenceCenter)]` for convenient frame and center definitions.
5//!
6//! ## Usage
7//!
8//! These derives are re-exported from `affn`, so you typically use them as:
9//!
10//! ```rust,ignore
11//! use affn::{ReferenceFrame, ReferenceCenter};
12//!
13//! #[derive(Debug, Copy, Clone, ReferenceFrame)]
14//! struct MyFrame;
15//!
16//! #[derive(Debug, Copy, Clone, ReferenceCenter)]
17//! struct MyCenter;
18//! ```
19//!
20//! ## Attributes
21//!
22//! ### `#[derive(ReferenceFrame)]`
23//!
24//! - `#[frame(name = "CustomName")]` - Override the frame name (defaults to struct name)
25//! - `#[frame(polar = "dec", azimuth = "ra")]` - Also implement `SphericalNaming` with custom names
26//! - `#[frame(distance = "altitude")]` - Override distance name (defaults to "distance")
27//! - `#[frame(inherent)]` - Generate inherent methods on `Direction<F>` and `Position<C,F,U>`.
28//!   Only valid when the frame is defined in the same crate as `Direction`/`Position`.
29//! - `#[frame(ellipsoid = "Wgs84")]` - Also implement `HasEllipsoid` for the frame.
30//!
31//! ### `#[derive(ReferenceCenter)]`
32//!
33//! - `#[center(name = "CustomName")]` - Override the center name (defaults to struct name)
34//! - `#[center(params = MyParamsType)]` - Specify the `Params` associated type (defaults to `()`)
35//! - `#[center(affine = false)]` - Skip implementing `AffineCenter` marker trait
36
37use proc_macro::TokenStream;
38use syn::{parse_macro_input, DeriveInput};
39
40mod center;
41mod frame;
42
43// =============================================================================
44// ReferenceFrame derive
45// =============================================================================
46
47/// Derive macro for implementing [`ReferenceFrame`](affn::frames::ReferenceFrame).
48///
49/// # Example
50///
51/// ```rust,ignore
52/// use affn::ReferenceFrame;
53///
54/// #[derive(Debug, Copy, Clone, ReferenceFrame)]
55/// struct ICRS;
56///
57/// assert_eq!(ICRS::frame_name(), "ICRS");
58/// ```
59///
60/// ## Custom Name
61///
62/// ```rust,ignore
63/// #[derive(Debug, Copy, Clone, ReferenceFrame)]
64/// #[frame(name = "International Celestial Reference System")]
65/// struct ICRS;
66///
67/// assert_eq!(ICRS::frame_name(), "International Celestial Reference System");
68/// ```
69///
70/// ## SphericalNaming
71///
72/// When `polar` and `azimuth` attributes are provided, the macro also implements
73/// [`SphericalNaming`](affn::frames::SphericalNaming):
74///
75/// ```rust,ignore
76/// #[derive(Debug, Copy, Clone, ReferenceFrame)]
77/// #[frame(polar = "dec", azimuth = "ra")]
78/// struct ICRS;
79///
80/// assert_eq!(ICRS::polar_name(), "dec");
81/// assert_eq!(ICRS::azimuth_name(), "ra");
82/// assert_eq!(ICRS::distance_name(), "distance"); // default
83/// ```
84///
85/// With custom distance name:
86///
87/// ```rust,ignore
88/// #[derive(Debug, Copy, Clone, ReferenceFrame)]
89/// #[frame(polar = "lat", azimuth = "lon", distance = "altitude")]
90/// struct ITRF;
91/// ```
92#[proc_macro_derive(ReferenceFrame, attributes(frame))]
93pub fn derive_reference_frame(input: TokenStream) -> TokenStream {
94    let input = parse_macro_input!(input as DeriveInput);
95    match frame::derive_reference_frame_impl(input) {
96        Ok(tokens) => tokens.into(),
97        Err(err) => err.to_compile_error().into(),
98    }
99}
100
101// =============================================================================
102// ReferenceCenter derive
103// =============================================================================
104
105/// Derive macro for implementing [`ReferenceCenter`](affn::centers::ReferenceCenter).
106///
107/// By default, this also implements [`AffineCenter`](affn::centers::AffineCenter).
108///
109/// # Example
110///
111/// ```rust,ignore
112/// use affn::ReferenceCenter;
113///
114/// #[derive(Debug, Copy, Clone, ReferenceCenter)]
115/// struct Heliocentric;
116///
117/// assert_eq!(Heliocentric::center_name(), "Heliocentric");
118/// ```
119///
120/// ## Custom Parameters
121///
122/// ```rust,ignore
123/// use affn::ReferenceCenter;
124///
125/// #[derive(Clone, Debug, Default, PartialEq)]
126/// struct ObserverLocation {
127///     lat: f64,
128///     lon: f64,
129/// }
130///
131/// #[derive(Debug, Copy, Clone, ReferenceCenter)]
132/// #[center(params = ObserverLocation)]
133/// struct Topocentric;
134/// ```
135///
136/// ## Skip AffineCenter
137///
138/// ```rust,ignore
139/// #[derive(Debug, Copy, Clone, ReferenceCenter)]
140/// #[center(affine = false)]
141/// struct NonAffineCenter;
142/// ```
143#[proc_macro_derive(ReferenceCenter, attributes(center))]
144pub fn derive_reference_center(input: TokenStream) -> TokenStream {
145    let input = parse_macro_input!(input as DeriveInput);
146    match center::derive_reference_center_impl(input) {
147        Ok(tokens) => tokens.into(),
148        Err(err) => err.to_compile_error().into(),
149    }
150}