1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{self, parse_macro_input, Data, DeriveInput, Ident};
4
5enum Ops {
6 Add,
7 Sub,
8 Mul,
9 Div,
10 AddAssign,
11 SubAssign,
12 MulAssign,
13 DivAssign,
14}
15
16fn parse(ast: DeriveInput) -> (Ident, Vec<Ident>) {
17 let name = ast.ident;
18 let struct_fields = if let Data::Struct(struct_data) = ast.data {
19 struct_data.fields
20 } else {
21 panic!("Expected a struct!")
22 };
23
24 let mut field_names = vec![];
25
26 for field in struct_fields {
27 field_names.push(field.ident.unwrap());
28 }
29
30 (name, field_names)
31}
32
33#[proc_macro_derive(AutoAdd)]
34pub fn derive_add(input: TokenStream) -> TokenStream {
35 complete(input, Ops::Add)
36}
37
38#[proc_macro_derive(AutoSub)]
39pub fn derive_sub(input: TokenStream) -> TokenStream {
40 complete(input, Ops::Sub)
41}
42
43#[proc_macro_derive(AutoMul)]
44pub fn derive_mul(input: TokenStream) -> TokenStream {
45 complete(input, Ops::Mul)
46}
47
48#[proc_macro_derive(AutoDiv)]
49pub fn derive_div(input: TokenStream) -> TokenStream {
50 complete(input, Ops::Div)
51}
52
53#[proc_macro_derive(AutoAddAssign)]
54pub fn derive_add_assign(input: TokenStream) -> TokenStream {
55 complete(input, Ops::AddAssign)
56}
57
58#[proc_macro_derive(AutoSubAssign)]
59pub fn derive_sub_assign(input: TokenStream) -> TokenStream {
60 complete(input, Ops::SubAssign)
61}
62
63#[proc_macro_derive(AutoMulAssign)]
64pub fn derive_mul_assign(input: TokenStream) -> TokenStream {
65 complete(input, Ops::MulAssign)
66}
67
68#[proc_macro_derive(AutoDivAssign)]
69pub fn derive_div_assign(input: TokenStream) -> TokenStream {
70 complete(input, Ops::DivAssign)
71}
72
73#[proc_macro_derive(AutoNeg)]
74pub fn derive_neg(input: TokenStream) -> TokenStream {
75 let (name, fields) = parse(parse_macro_input!(input as DeriveInput));
76
77 let ret = quote! {
78 impl ::std::ops::Neg for #name {
79 type Output = Self;
80
81 fn neg(self) -> Self::Output {
82 #name {
83 #(
84 #fields: -self.#fields,
85 )*
86 }
87 }
88 }
89 };
90 ret.into()
91}
92
93#[proc_macro_derive(AutoAll)]
94pub fn derive_all(input: TokenStream) -> TokenStream {
95 let (name, fields) = parse(parse_macro_input!(input as DeriveInput));
96
97 let add: proc_macro2::TokenStream = complete_internal(&name, &fields, Ops::Add).into();
98 let sub: proc_macro2::TokenStream = complete_internal(&name, &fields, Ops::Sub).into();
99 let mul: proc_macro2::TokenStream = complete_internal(&name, &fields, Ops::Mul).into();
100 let div: proc_macro2::TokenStream = complete_internal(&name, &fields, Ops::Div).into();
101 let add_assign: proc_macro2::TokenStream =
102 complete_internal(&name, &fields, Ops::AddAssign).into();
103 let sub_assign: proc_macro2::TokenStream =
104 complete_internal(&name, &fields, Ops::SubAssign).into();
105 let mul_assign: proc_macro2::TokenStream =
106 complete_internal(&name, &fields, Ops::MulAssign).into();
107 let div_assign: proc_macro2::TokenStream =
108 complete_internal(&name, &fields, Ops::DivAssign).into();
109 let ret = quote! {
110 #add
111 #sub
112 #mul
113 #div
114 #add_assign
115 #sub_assign
116 #mul_assign
117 #div_assign
118
119 impl ::std::ops::Neg for #name {
120 type Output = Self;
121
122 fn neg(self) -> Self::Output {
123 #name {
124 #(
125 #fields: -self.#fields,
126 )*
127 }
128 }
129 }
130 };
131 ret.into()
132}
133
134fn complete(input: TokenStream, trait_: Ops) -> TokenStream {
135 let (name, fields) = parse(parse_macro_input!(input as DeriveInput));
136 complete_internal(&name, &fields, trait_)
137}
138
139fn complete_internal(name: &Ident, fields: &[Ident], trait_: Ops) -> TokenStream {
140 let (trait_name, func_header, operation) = match trait_ {
141 Ops::Add => (
142 quote! {Add},
143 quote! {add(self, rhs: Self) -> Self::Output},
144 quote! {+},
145 ),
146 Ops::Sub => (
147 quote! {Sub},
148 quote! {sub(self, rhs: Self) -> Self::Output},
149 quote! {-},
150 ),
151 Ops::Mul => (
152 quote! {Mul},
153 quote! {mul(self, rhs: Self) -> Self::Output},
154 quote! {*},
155 ),
156 Ops::Div => (
157 quote! {Div},
158 quote! {div(self, rhs: Self) -> Self::Output},
159 quote! {/},
160 ),
161 Ops::AddAssign => (
162 quote! {AddAssign},
163 quote! {add_assign(&mut self, rhs: Self)},
164 quote! {+},
165 ),
166 Ops::SubAssign => (
167 quote! {SubAssign},
168 quote! {sub_assign(&mut self, rhs: Self)},
169 quote! {-},
170 ),
171 Ops::MulAssign => (
172 quote! {MulAssign},
173 quote! {mul_assign(&mut self, rhs: Self)},
174 quote! {*},
175 ),
176 Ops::DivAssign => (
177 quote! {DivAssign},
178 quote! {div_assign(&mut self, rhs: Self)},
179 quote! {/},
180 ),
181 };
182
183 let output = match trait_ {
184 Ops::Add | Ops::Sub | Ops::Mul | Ops::Div => quote! {type Output = Self;},
185 _ => quote! {},
186 };
187
188 let deref = match trait_ {
189 Ops::AddAssign | Ops::SubAssign | Ops::MulAssign | Ops::DivAssign => quote! {*self = },
190 _ => quote! {},
191 };
192
193 let ret = quote! {
194 impl ::std::ops::#trait_name for #name {
195 #output
196
197 fn #func_header {
198 #deref #name {
199 #(
200 #fields: self.#fields #operation rhs.#fields,
201 )*
202 }
203 }
204 }
205 };
206 ret.into()
207}