genetic_rs_macros/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use quote::quote_spanned;
6use syn::spanned::Spanned;
7use syn::{parse_macro_input, Data, DeriveInput};
8
9#[proc_macro_derive(RandomlyMutable)]
10pub fn randmut_derive(input: TokenStream) -> TokenStream {
11    let ast = parse_macro_input!(input as DeriveInput);
12
13    let name = ast.ident;
14
15    match ast.data {
16        Data::Struct(s) => {
17            let mut inner = Vec::new();
18
19            for (i, field) in s.fields.into_iter().enumerate() {
20                let ty = field.ty;
21                let span = ty.span();
22
23                if let Some(field_name) = field.ident {
24                    inner.push(quote_spanned! {span=>
25                        <#ty as genetic_rs_common::prelude::RandomlyMutable>::mutate(&mut self.#field_name, rate, rng);
26                    });
27                } else {
28                    inner.push(quote_spanned! {span=>
29                        <#ty as genetic_rs_common::prelude::RandomlyMutable>::mutate(&mut self.#i, rate, rng);
30                    });
31                }
32            }
33
34            let inner: proc_macro2::TokenStream = inner.into_iter().collect();
35
36            quote! {
37                impl genetic_rs_common::prelude::RandomlyMutable for #name {
38                    fn mutate(&mut self, rate: f32, rng: &mut impl genetic_rs_common::Rng) {
39                        #inner
40                    }
41                }
42            }
43            .into()
44        }
45        Data::Enum(_e) => {
46            panic!("enums not yet supported");
47        }
48        Data::Union(_u) => {
49            panic!("unions not yet supported");
50        }
51    }
52}
53
54#[proc_macro_derive(Mitosis)]
55pub fn mitosis_derive(input: TokenStream) -> TokenStream {
56    let ast = parse_macro_input!(input as DeriveInput);
57    let name = &ast.ident;
58
59    quote! {
60        impl genetic_rs_common::prelude::Mitosis for #name {}
61    }
62    .into()
63}
64
65#[cfg(feature = "crossover")]
66#[proc_macro_derive(Crossover)]
67pub fn crossover_derive(input: TokenStream) -> TokenStream {
68    let ast = parse_macro_input!(input as DeriveInput);
69
70    let name = ast.ident;
71
72    match ast.data {
73        Data::Struct(s) => {
74            let mut inner = Vec::new();
75            let mut tuple_struct = false;
76
77            for (i, field) in s.fields.into_iter().enumerate() {
78                let ty = field.ty;
79                let span = ty.span();
80
81                if let Some(field_name) = field.ident {
82                    inner.push(quote_spanned! {span=>
83                        #field_name: <#ty as genetic_rs_common::prelude::Crossover>::crossover(&self.#field_name, &other.#field_name, rate, rng),
84                    });
85                } else {
86                    tuple_struct = true;
87                    inner.push(quote_spanned! {span=>
88                        <#ty as genetic_rs_common::prelude::Crossover>::crossover(&self.#i, &other.#i, rate, rng),
89                    });
90                }
91            }
92
93            let inner: proc_macro2::TokenStream = inner.into_iter().collect();
94
95            if tuple_struct {
96                quote! {
97                    impl genetic_rs_common::prelude::Crossover for #name {
98                        fn crossover(&self, other: &Self, rate: f32, rng: &mut impl genetic_rs_common::Rng) -> Self {
99                            Self(#inner)
100                        }
101                    }
102                }.into()
103            } else {
104                quote! {
105                    impl genetic_rs_common::prelude::Crossover for #name {
106                        fn crossover(&self, other: &Self, rate: f32, rng: &mut impl genetic_rs_common::Rng) -> Self {
107                            Self {
108                                #inner
109                            }
110                        }
111                    }
112                }.into()
113            }
114        }
115        Data::Enum(_e) => {
116            panic!("enums not yet supported");
117        }
118        Data::Union(_u) => {
119            panic!("unions not yet supported");
120        }
121    }
122}
123
124#[cfg(feature = "genrand")]
125#[proc_macro_derive(GenerateRandom)]
126pub fn genrand_derive(input: TokenStream) -> TokenStream {
127    let ast = parse_macro_input!(input as DeriveInput);
128
129    let name = ast.ident;
130
131    match ast.data {
132        Data::Struct(s) => {
133            let mut inner = Vec::new();
134            let mut tuple_struct = false;
135
136            for field in s.fields {
137                let ty = field.ty;
138                let span = ty.span();
139
140                if let Some(field_name) = field.ident {
141                    inner.push(quote_spanned! {span=>
142                        #field_name: <#ty as genetic_rs_common::prelude::GenerateRandom>::gen_random(rng),
143                    });
144                } else {
145                    tuple_struct = true;
146                    inner.push(quote_spanned! {span=>
147                        <#ty as genetic_rs_common::prelude::GenerateRandom>::gen_random(rng),
148                    });
149                }
150            }
151
152            let inner: proc_macro2::TokenStream = inner.into_iter().collect();
153            if tuple_struct {
154                quote! {
155                    impl genetic_rs_common::prelude::GenerateRandom for #name {
156                        fn gen_random(rng: &mut impl genetic_rs_common::Rng) -> Self {
157                            Self(#inner)
158                        }
159                    }
160                }
161                .into()
162            } else {
163                quote! {
164                    impl genetic_rs_common::prelude::GenerateRandom for #name {
165                        fn gen_random(rng: &mut impl genetic_rs_common::Rng) -> Self {
166                            Self {
167                                #inner
168                            }
169                        }
170                    }
171                }
172                .into()
173            }
174        }
175        Data::Enum(_e) => {
176            panic!("enums not yet supported");
177        }
178        Data::Union(_u) => {
179            panic!("unions not yet supported");
180        }
181    }
182}