geometry_macros/
lib.rs

1//! Macros for the `geometry` crate.
2#![warn(missing_docs)]
3
4use macrotools::{
5    DeriveInputHelper, DeriveTrait, ImplTrait, MapField, Receiver, derive_trait, handle_syn_error,
6};
7use proc_macro::TokenStream;
8use proc_macro_crate::{FoundCrate, crate_name};
9use proc_macro2::{Span, TokenStream as TokenStream2};
10use quote::quote;
11use syn::{DeriveInput, Ident, parse_macro_input, parse_quote};
12
13pub(crate) fn geometry_ident() -> TokenStream2 {
14    match crate_name("geometry") {
15        Ok(FoundCrate::Itself) => quote!(::geometry),
16        Ok(FoundCrate::Name(name)) => {
17            let ident = Ident::new(&name, Span::call_site());
18            quote!(::#ident)
19        }
20        Err(_) => match crate_name("substrate").expect("geometry not found in Cargo.toml") {
21            FoundCrate::Itself => quote!(::substrate::geometry),
22            FoundCrate::Name(name) => {
23                let ident = Ident::new(&name, Span::call_site());
24                quote!(::#ident::geometry)
25            }
26        },
27    }
28}
29
30/// Derives `geometry::transform::TranslateMut`.
31#[proc_macro_derive(TranslateMut)]
32pub fn derive_translate_mut(input: TokenStream) -> TokenStream {
33    let parsed = parse_macro_input!(input as DeriveInput);
34    let geometry = geometry_ident();
35    let config = DeriveTrait {
36        trait_: quote!(#geometry::transform::TranslateMut),
37        method: quote!(translate_mut),
38        receiver: Receiver::MutRef,
39        extra_arg_idents: vec![quote!(__geometry_derive_point)],
40        extra_arg_tys: vec![quote!(#geometry::point::Point)],
41    };
42
43    let expanded = derive_trait(&config, &parsed);
44    proc_macro::TokenStream::from(expanded)
45}
46
47pub(crate) fn impl_translate_ref(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
48    let geometry = geometry_ident();
49    let helper = DeriveInputHelper::new(input.clone())?;
50    let body = helper.map_data(&parse_quote! { Self }, |MapField { ty, refer, .. }| {
51        quote! { <#ty as #geometry::transform::TranslateRef>::translate_ref(#refer, __geometry_derive_point) }
52    });
53    Ok(helper.impl_trait(&ImplTrait {
54        trait_name: quote! { #geometry::transform::TranslateRef },
55        trait_body: quote! {
56            fn translate_ref(&self, __geometry_derive_point: #geometry::point::Point) -> Self {
57                #body
58            }
59        },
60        extra_generics: vec![],
61        extra_where_predicates: vec![],
62    }))
63}
64
65/// Derives `geometry::transform::TranslateRef`.
66#[proc_macro_derive(TranslateRef)]
67pub fn derive_translate_ref(input: TokenStream) -> TokenStream {
68    let parsed = parse_macro_input!(input as DeriveInput);
69    let output = handle_syn_error!(impl_translate_ref(&parsed));
70    quote!(
71        #output
72    )
73    .into()
74}
75
76/// Derives `geometry::transform::TransformMut`.
77#[proc_macro_derive(TransformMut)]
78pub fn derive_transform_mut(input: TokenStream) -> TokenStream {
79    let parsed = parse_macro_input!(input as DeriveInput);
80    let geometry = geometry_ident();
81    let config = DeriveTrait {
82        trait_: quote!(#geometry::transform::TransformMut),
83        method: quote!(transform_mut),
84        receiver: Receiver::MutRef,
85        extra_arg_idents: vec![quote!(__geometry_derive_transformation)],
86        extra_arg_tys: vec![quote!(#geometry::transform::Transformation)],
87    };
88
89    let expanded = derive_trait(&config, &parsed);
90    proc_macro::TokenStream::from(expanded)
91}
92
93pub(crate) fn impl_transform_ref(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
94    let geometry = geometry_ident();
95    let helper = DeriveInputHelper::new(input.clone())?;
96    let body = helper.map_data(&parse_quote! { Self }, |MapField { ty, refer, .. }| {
97        quote! { <#ty as #geometry::transform::TransformRef>::transform_ref(#refer, __geometry_derive_transformation) }
98    });
99    Ok(helper.impl_trait(&ImplTrait {
100        trait_name: quote! { #geometry::transform::TransformRef },
101        trait_body: quote! {
102            fn transform_ref(&self, __geometry_derive_transformation: #geometry::transform::Transformation) -> Self {
103                #body
104            }
105        },
106        extra_generics: vec![],
107        extra_where_predicates: vec![],
108    }))
109}
110
111/// Derives `geometry::transform::TransformRef`.
112#[proc_macro_derive(TransformRef)]
113pub fn derive_transform_ref(input: TokenStream) -> TokenStream {
114    let parsed = parse_macro_input!(input as DeriveInput);
115    let output = handle_syn_error!(impl_transform_ref(&parsed));
116    quote!(
117        #output
118    )
119    .into()
120}