1 | //! Provides a macro to simplify operator overloading. |
---|---|
2 | //! |
3 | //! To use, include the following: |
4 | //! ``` |
5 | //! extern crate overload; |
6 | //! use overload::overload; |
7 | //! use std::ops; // <- don't forget this or you'll get nasty errors |
8 | //! ``` |
9 | //! |
10 | //! # Introduction |
11 | //! |
12 | //! Suppose we have the following `struct` definition: |
13 | //! ``` |
14 | //! #[derive(PartialEq, Debug)] |
15 | //! struct Val { |
16 | //! v: i32 |
17 | //! } |
18 | //! ``` |
19 | //! We can overload the addition of `Val`s like so: |
20 | //! ``` |
21 | //! # extern crate overload; |
22 | //! # use overload::overload; |
23 | //! # use std::ops; |
24 | //! # #[derive(PartialEq, Debug)] |
25 | //! # struct Val { |
26 | //! # v: i32 |
27 | //! # } |
28 | //! overload!((a: Val) + (b: Val) -> Val { Val { v: a.v + b.v } }); |
29 | //! ``` |
30 | //! The macro call above generates the following code: |
31 | //! ```ignore |
32 | //! impl ops::Add<Val> for Val { |
33 | //! type Output = Val; |
34 | //! fn add(self, b: Val) -> Self::Output { |
35 | //! let a = self; |
36 | //! Val { v: a.v + b.v } |
37 | //! } |
38 | //! } |
39 | //! ``` |
40 | //! We are now able to add `Val`s: |
41 | //! ``` |
42 | //! # extern crate overload; |
43 | //! # use overload::overload; |
44 | //! # use std::ops; |
45 | //! # #[derive(PartialEq, Debug)] |
46 | //! # struct Val { |
47 | //! # v: i32 |
48 | //! # } |
49 | //! # overload!((a: Val) + (b: Val) -> Val { Val { v: a.v + b.v } }); |
50 | //! assert_eq!(Val{v:3} + Val{v:5}, Val{v:8}); |
51 | //! ``` |
52 | //! |
53 | //! # Owned and borrowed types |
54 | //! |
55 | //! If we also wanted to overload addition for the borrowed type `&Val` we could write: |
56 | //! ``` |
57 | //! # extern crate overload; |
58 | //! # use overload::overload; |
59 | //! # use std::ops; |
60 | //! # #[derive(PartialEq, Debug)] |
61 | //! # struct Val { |
62 | //! # v: i32 |
63 | //! # } |
64 | //! overload!((a: &Val) + (b: &Val) -> Val { Val { v: a.v + b.v } }); |
65 | //! ``` |
66 | //! We might also want to overload addition between the owned and borrowed types: |
67 | //! ``` |
68 | //! # extern crate overload; |
69 | //! # use overload::overload; |
70 | //! # use std::ops; |
71 | //! # #[derive(PartialEq, Debug)] |
72 | //! # struct Val { |
73 | //! # v: i32 |
74 | //! # } |
75 | //! overload!((a: Val) + (b: &Val) -> Val { Val { v: a.v + b.v } }); |
76 | //! overload!((a: &Val) + (b: Val) -> Val { Val { v: a.v + b.v } }); |
77 | //! ``` |
78 | //! Let's see how we can write these combinations more concisely. |
79 | //! |
80 | //! We can include a `?` in front of a type to indicate that it should stand in for both the owned and borrowed type. |
81 | //! |
82 | //! To overload addition for all four combinations between `Val` and `&Val` we can therefore simply include a `?` in front of both types: |
83 | //! ``` |
84 | //! # extern crate overload; |
85 | //! # use overload::overload; |
86 | //! # use std::ops; |
87 | //! # #[derive(PartialEq, Debug)] |
88 | //! # struct Val { |
89 | //! # v: i32 |
90 | //! # } |
91 | //! overload!((a: ?Val) + (b: ?Val) -> Val { Val { v: a.v + b.v } }); |
92 | //! ``` |
93 | //! The macro call above generates the following code: |
94 | //! ```ignore |
95 | //! impl ops::Add<Val> for Val { |
96 | //! type Output = Val; |
97 | //! fn add(self, b: Val) -> Self::Output { |
98 | //! let a = self; |
99 | //! Val { v: a.v + b.v } |
100 | //! } |
101 | //! } |
102 | //! |
103 | //! impl ops::Add<&Val> for Val { |
104 | //! type Output = Val; |
105 | //! fn add(self, b: &Val) -> Self::Output { |
106 | //! let a = self; |
107 | //! Val { v: a.v + b.v } |
108 | //! } |
109 | //! } |
110 | //! |
111 | //! impl ops::Add<Val> for &Val { |
112 | //! type Output = Val; |
113 | //! fn add(self, b: Val) -> Self::Output { |
114 | //! let a = self; |
115 | //! Val { v: a.v + b.v } |
116 | //! } |
117 | //! } |
118 | //! |
119 | //! impl ops::Add<&Val> for &Val { |
120 | //! type Output = Val; |
121 | //! fn add(self, b: &Val) -> Self::Output { |
122 | //! let a = self; |
123 | //! Val { v: a.v + b.v } |
124 | //! } |
125 | //! } |
126 | //! ``` |
127 | //! We are now able to add `Val`s and `&Val`s in any combination: |
128 | //! ``` |
129 | //! # extern crate overload; |
130 | //! # use overload::overload; |
131 | //! # use std::ops; |
132 | //! # #[derive(PartialEq, Debug)] |
133 | //! # struct Val { |
134 | //! # v: i32 |
135 | //! # } |
136 | //! # overload!((a: ?Val) + (b: ?Val) -> Val { Val { v: a.v + b.v } }); |
137 | //! assert_eq!(Val{v:3} + Val{v:5}, Val{v:8}); |
138 | //! assert_eq!(Val{v:3} + &Val{v:5}, Val{v:8}); |
139 | //! assert_eq!(&Val{v:3} + Val{v:5}, Val{v:8}); |
140 | //! assert_eq!(&Val{v:3} + &Val{v:5}, Val{v:8}); |
141 | //! ``` |
142 | //! |
143 | //! # Binary operators |
144 | //! |
145 | //! The general syntax to overload a binary operator between types `<a_type>` and `<b_type>` is: |
146 | //! ```ignore |
147 | //! overload!((<a_ident>: <a_type>) <op> (<b_ident>: <b_type>) -> <out_type> { /*body*/ }); |
148 | //! ``` |
149 | //! Inside the body you can use `<a_ident>` and `<b_ident>` freely to perform any computation. |
150 | //! |
151 | //! The last line of the body needs to be an expression (i.e. no `;` at the end of the line) of type `<out_type>`. |
152 | //! |
153 | //! | Operator | Example | Trait | |
154 | //! |----------|-----------------------------------------------------------------|--------| |
155 | //! | + | `overload!((a: A) + (b: B) -> C { /*...*/ );` | Add | |
156 | //! | - | `overload!((a: A) - (b: B) -> C { /*...*/ );` | Sub | |
157 | //! | * | `overload!((a: A) * (b: B) -> C { /*...*/ );` | Mul | |
158 | //! | / | `overload!((a: A) / (b: B) -> C { /*...*/ );` | Div | |
159 | //! | % | `overload!((a: A) % (b: B) -> C { /*...*/ );` | Rem | |
160 | //! | & | `overload!((a: A) & (b: B) -> C { /*...*/ );` | BitAnd | |
161 | //! | \| | <code>overload!((a: A) | (b: B) -> C { /\*...*\/ );</code> | BitOr | |
162 | //! | ^ | `overload!((a: A) ^ (b: B) -> C { /*...*/ );` | BitXor | |
163 | //! | << | `overload!((a: A) << (b: B) -> C { /*...*/ );` | Shl | |
164 | //! | >> | `overload!((a: A) >> (b: B) -> C { /*...*/ );` | Shr | |
165 | //! |
166 | //! # Assignment operators |
167 | //! |
168 | //! The general syntax to overload an assignment operator between types `<a_type>` and `<b_type>` is: |
169 | //! ```ignore |
170 | //! overload!((<a_ident>: &mut <a_type>) <op> (<b_ident>: <b_type>) { /*body*/ }); |
171 | //! ``` |
172 | //! Inside the body you can use `<a_ident>` and `<b_ident>` freely to perform any computation and mutate `<a_ident>` as desired. |
173 | //! |
174 | //! | Operator | Example | Trait | |
175 | //! |----------|------------------------------------------------------------------|--------------| |
176 | //! | += | `overload!((a: &mut A) += (b: B) { /*...*/ );` | AddAssign | |
177 | //! | -= | `overload!((a: &mut A) -= (b: B) { /*...*/ );` | SubAssign | |
178 | //! | *= | `overload!((a: &mut A) *= (b: B) { /*...*/ );` | MulAssign | |
179 | //! | /= | `overload!((a: &mut A) /= (b: B) { /*...*/ );` | DivAssign | |
180 | //! | %= | `overload!((a: &mut A) %= (b: B) { /*...*/ );` | RemAssign | |
181 | //! | &= | `overload!((a: &mut A) &= (b: B) { /*...*/ );` | BitAndAssign | |
182 | //! | \|= | <code>overload!((a: &mut A) |= (b: B) { /\*...*\/ );</code> | BitOrAssign | |
183 | //! | ^= | `overload!((a: &mut A) ^= (b: B) { /*...*/ );` | BitXorAssign | |
184 | //! | <<= | `overload!((a: &mut A) <<= (b: B) { /*...*/ );` | ShlAssign | |
185 | //! | >>= | `overload!((a: &mut A) >>= (b: B) { /*...*/ );` | ShrAssign | |
186 | //! |
187 | //! # Unary operators |
188 | //! |
189 | //! The general syntax to overload a unary operator for type `<a_type>` is: |
190 | //! ```ignore |
191 | //! overload!(<op> (<a_ident>: <a_type>) -> <out_type> { /*body*/ }); |
192 | //! ``` |
193 | //! Inside the body you can use `<a_ident>` freely to perform any computation. |
194 | //! |
195 | //! The last line of the body needs to be an expression (i.e. no `;` at the end of the line) of type `<out_type>`. |
196 | //! |
197 | //! | Operator | Example | Trait | |
198 | //! |----------|---------------------------------------------------------|-------| |
199 | //! | - | `overload!(- (a: A) -> B { /*...*/ );` | Neg | |
200 | //! | ! | `overload!(! (a: A) -> B { /*...*/ );` | Not | |
201 | //! |
202 | //! # Notes |
203 | //! |
204 | //! Remember that you can only overload operators between one or more types if at least one of the types is defined in the current crate. |
205 | |
206 | #[macro_use] |
207 | mod unary; |
208 | |
209 | #[macro_use] |
210 | mod assignment; |
211 | |
212 | #[macro_use] |
213 | mod binary; |
214 | |
215 | /// Overloads an operator. See the [module level documentation](index.html) for more information. |
216 | #[macro_export(local_inner_macros)] |
217 | macro_rules! overload { |
218 | // Unary (both owned and borrowed) |
219 | ($op:tt ($i:ident : ? $t:ty) -> $out:ty $body:block) => ( |
220 | _overload_unary!($op, $i, $t, $out, $body); |
221 | _overload_unary!($op, $i, &$t, $out, $body); |
222 | ); |
223 | // Unary (either owned or borrowed) |
224 | ($op:tt ($i:ident : $t:ty) -> $out:ty $body:block) => ( |
225 | _overload_unary!($op, $i, $t, $out, $body); |
226 | ); |
227 | // Assignment (both owned and borrowed) |
228 | (($li:ident : &mut $lt:ty) $op:tt ($ri:ident : ? $rt:ty) $body:block) => ( |
229 | _overload_assignment!($op, $li, $lt, $ri, $rt, $body); |
230 | _overload_assignment!($op, $li, $lt, $ri, &$rt, $body); |
231 | ); |
232 | // Assignment (either owned or borrowed) |
233 | (($li:ident : &mut $lt:ty) $op:tt ($ri:ident : $rt:ty) $body:block) => ( |
234 | _overload_assignment!($op, $li, $lt, $ri, $rt, $body); |
235 | ); |
236 | // Binary (both - both) |
237 | (($li:ident : ? $lt:ty) $op:tt ($ri:ident : ? $rt:ty) -> $out:ty $body:block) => ( |
238 | _overload_binary!($op, $li, $lt, $ri, $rt, $out, $body); |
239 | _overload_binary!($op, $li, $lt, $ri, &$rt, $out, $body); |
240 | _overload_binary!($op, $li, &$lt, $ri, $rt, $out, $body); |
241 | _overload_binary!($op, $li, &$lt, $ri, &$rt, $out, $body); |
242 | ); |
243 | // Binary (both - either) |
244 | (($li:ident : ? $lt:ty) $op:tt ($ri:ident : $rt:ty) -> $out:ty $body:block) => ( |
245 | _overload_binary!($op, $li, $lt, $ri, $rt, $out, $body); |
246 | _overload_binary!($op, $li, &$lt, $ri, $rt, $out, $body); |
247 | ); |
248 | // Binary (either - both) |
249 | (($li:ident : $lt:ty) $op:tt ($ri:ident : ? $rt:ty) -> $out:ty $body:block) => ( |
250 | _overload_binary!($op, $li, $lt, $ri, $rt, $out, $body); |
251 | _overload_binary!($op, $li, $lt, $ri, &$rt, $out, $body); |
252 | ); |
253 | // Binary (either - either) |
254 | (($li:ident : $lt:ty) $op:tt ($ri:ident : $rt:ty) -> $out:ty $body:block) => ( |
255 | _overload_binary!($op, $li, $lt, $ri, $rt, $out, $body); |
256 | ); |
257 | } |
258 |
Definitions
Learn Rust with the experts
Find out more