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}