autd3_traits/
lib.rs

1/*
2 * File: lib.rs
3 * Project: src
4 * Created Date: 28/04/2022
5 * Author: Shun Suzuki
6 * -----
7 * Last Modified: 27/07/2023
8 * Modified By: Shun Suzuki (suzuki@hapis.k.u-tokyo.ac.jp)
9 * -----
10 * Copyright (c) 2022-2023 Shun Suzuki. All rights reserved.
11 *
12 */
13
14use proc_macro::TokenStream;
15use quote::quote;
16
17#[proc_macro_derive(Modulation)]
18pub fn modulation_derive(input: TokenStream) -> TokenStream {
19    let ast = syn::parse(input).unwrap();
20    impl_modulation_macro(&ast)
21}
22
23fn impl_modulation_macro(ast: &syn::DeriveInput) -> TokenStream {
24    let name = &ast.ident;
25    let generics = &ast.generics;
26    let linetimes_prop = generics.lifetimes();
27    let linetimes_impl = generics.lifetimes();
28    let linetimes_datagram = generics.lifetimes();
29    let type_params_prop = generics.type_params();
30    let type_params_impl = generics.type_params();
31    let type_params_datagram = generics.type_params();
32    let (_, ty_generics, where_clause) = generics.split_for_impl();
33    let gen = quote! {
34        impl <#(#linetimes_prop,)* #(#type_params_prop,)*> autd3_core::modulation::ModulationProperty for #name #ty_generics #where_clause {
35            fn sampling_frequency_division(&self) -> u32 {
36                self.freq_div
37            }
38
39            fn sampling_frequency(&self) -> autd3_core::float {
40                autd3_core::FPGA_SUB_CLK_FREQ as autd3_core::float / self.freq_div as autd3_core::float
41            }
42        }
43
44        impl <#(#linetimes_impl,)* #(#type_params_impl,)*> #name #ty_generics #where_clause {
45            /// Set sampling frequency division
46            ///
47            /// # Arguments
48            ///
49            /// * `freq_div` - Sampling frequency division. The sampling frequency will be [autd3_core::FPGA_SUB_CLK_FREQ] / `freq_div`. The value must be and must be at least [autd3_core::SAMPLING_FREQ_DIV_MIN]
50            ///
51            #[allow(clippy::needless_update)]
52            pub fn with_sampling_frequency_division(self, freq_div: u32) -> Self {
53                Self {freq_div, ..self}
54            }
55
56            /// Set sampling frequency
57            ///
58            /// # Arguments
59            ///
60            /// * `freq` - Sampling frequency. The sampling frequency closest to `freq` from the possible sampling frequencies is set.
61            ///
62            #[allow(clippy::needless_update)]
63            pub fn with_sampling_frequency(self, freq: autd3_core::float) -> Self {
64                let freq_div = autd3_core::FPGA_SUB_CLK_FREQ as autd3_core::float / freq;
65                self.with_sampling_frequency_division(freq_div as _)
66            }
67
68            /// Set sampling period
69            ///
70            /// # Arguments
71            ///
72            /// * `period` - Sampling period. The sampling period closest to `period` from the possible sampling periods is set.
73            ///
74            #[allow(clippy::needless_update)]
75            pub fn with_sampling_period(self, period: std::time::Duration) -> Self {
76                let freq_div = autd3_core::FPGA_SUB_CLK_FREQ as autd3_core::float / 1000000000. * period.as_nanos() as autd3_core::float;
77                self.with_sampling_frequency_division(freq_div as _)
78            }
79        }
80
81        impl <#(#linetimes_datagram,)* #(#type_params_datagram,)* T: autd3_core::geometry::Transducer> autd3_core::datagram::Datagram<T> for #name #ty_generics #where_clause {
82            type H = autd3_core::Modulation;
83            type B = autd3_core::NullBody;
84
85            fn operation(
86                &self,
87                _geometry: &autd3_core::geometry::Geometry<T>,
88            ) -> Result<(Self::H, Self::B), autd3_core::error::AUTDInternalError> {
89                let freq_div = self.freq_div;
90                Ok((Self::H::new(self.calc()?, freq_div), Self::B::default()))
91            }
92        }
93    };
94    gen.into()
95}
96
97#[proc_macro_derive(Gain)]
98pub fn gain_derive(input: TokenStream) -> TokenStream {
99    let ast = syn::parse(input).unwrap();
100    impl_gain_macro(ast)
101}
102
103fn impl_gain_macro(ast: syn::DeriveInput) -> TokenStream {
104    let name = &ast.ident;
105    let generics = &ast.generics;
106    let linetimes_for_any = generics.lifetimes();
107    let linetimes = generics.lifetimes();
108    let type_params_for_any = generics.type_params();
109    let type_params = generics.type_params();
110    let (_, ty_generics, where_clause) = generics.split_for_impl();
111    if generics.type_params().any(|ty| ty.ident == "T") {
112        let gen = quote! {
113            impl <#(#linetimes_for_any,)* #(#type_params_for_any,)*> autd3_core::gain::GainAsAny for #name #ty_generics #where_clause {
114                fn as_any(&self) -> &dyn std::any::Any {
115                    self
116                }
117            }
118
119            impl <#(#linetimes,)* #(#type_params,)*> autd3_core::datagram::Datagram<T> for #name #ty_generics #where_clause {
120                type H = autd3_core::NullHeader;
121                type B = T::Gain;
122
123                fn operation(
124                    &self,
125                    geometry: &Geometry<T>,
126                ) -> Result<(Self::H, Self::B), autd3_core::error::AUTDInternalError> {
127                    Ok((Self::H::default(), <Self::B as autd3_core::GainOp>::new(self.calc(geometry)?, || {
128                        geometry.transducers().map(|tr| tr.cycle()).collect()
129                    })))
130                }
131            }
132        };
133        gen.into()
134    } else {
135        let gen = quote! {
136            impl <#(#linetimes_for_any,)* #(#type_params_for_any,)*> autd3_core::gain::GainAsAny for #name #ty_generics #where_clause {
137                fn as_any(&self) -> &dyn std::any::Any {
138                    self
139                }
140            }
141
142            impl <#(#linetimes,)* #(#type_params,)* T: autd3_core::geometry::Transducer> autd3_core::datagram::Datagram<T> for #name #ty_generics #where_clause {
143                type H = autd3_core::NullHeader;
144                type B = T::Gain;
145
146                fn operation(
147                    &self,
148                    geometry: &Geometry<T>,
149                ) -> Result<(Self::H, Self::B), autd3_core::error::AUTDInternalError> {
150                    Ok((Self::H::default(), <Self::B as autd3_core::GainOp>::new(self.calc(geometry)?, || {
151                        geometry.transducers().map(|tr| tr.cycle()).collect()
152                    })))
153                }
154            }
155        };
156        gen.into()
157    }
158}