deltastruct/lib.rs
1//! Create custom serializable changes to apply later
2//!
3//! Deltastruct is an attribute macro that generates definitions for
4//! serializable changes (called deltas) over structs recursively.
5//!
6//! For techinical reasons, the attribute macro must be applied to a `mod`
7//! definition containing a `struct` with the same name and an `impl` for
8//! it's change definitions. Function names are converted to camel case to
9//! appease the compiler.
10//!
11//! The generated deltas are always the type name followed by `Delta`. ie: `Foo` -> `FooDelta`, `i32` -> `i32Delta`.
12//!
13//! ```
14//! # use deltastruct::*;
15//! #[deltastruct]
16//! mod Vector3 {
17//! #[derive(Clone, Copy)]
18//! pub struct Vector3 {
19//! pub x : f64,
20//! pub y : f64,
21//! pub z : f64,
22//! }
23//!
24//! impl Vector3 {
25//! fn set(&mut self, other : Vector3) {
26//! // Copy the given vec's components into our own.
27//! self.x = other.x;
28//! self.y = other.y;
29//! self.z = other.z;
30//! }
31//!
32//! fn multiply_scalar(&mut self, n : f64) {
33//! // Multiply each component by the given value
34//! self.x *= n;
35//! self.y *= n;
36//! self.z *= n;
37//! }
38//!
39//! fn normalize(&mut self) {
40//! // divide each component by the vector's magnitude
41//! let magnitude = (
42//! self.x.powf(2f64)
43//! + self.y.powf(2f64)
44//! + self.z.powf(2f64)
45//! ).sqrt();
46//!
47//! self.x /= magnitude;
48//! self.y /= magnitude;
49//! self.z /= magnitude;
50//! }
51//! }
52//! }
53//!
54//! fn main() {
55//! let mut v = Vector3 {
56//! x: 3f64,
57//! y: 6f64,
58//! z: 6f64
59//! };
60//!
61//!
62//! let v_delta = Vector3Delta::MultiplyScalar(4f64);
63//! v.apply(&v_delta);
64//! v.apply(&v_delta);
65//!
66//! assert_eq!(v.x, 48f64);
67//!
68//!
69//! let v_delta = Vector3Delta::Normalize();
70//! v.apply(&v_delta);
71//!
72//! assert_eq!(v.z, 2f64/3f64);
73//!
74//!
75//! let v_delta = Vector3Delta::X(f64Delta::Set(8f64));
76//! v.apply(&v_delta);
77//!
78//! assert_eq!(v.x, 8f64);
79//! }
80//!
81//! ```
82//!
83//!
84
85mod primitive_impls;
86pub use primitive_impls::*;
87
88/// An attribute macro applied to `mod`s. Will generate a Delta and it's `DeltaStruct<_>` implementation.
89///
90/// Applied to a `mod`. Expects the `mod` to have a `struct` with the same name
91/// and an implementation. Currently at least one field is expected in the `struct`
92/// definition and at least one method is expected in the implementation. This macro
93/// will generate an `enum` with the same name as the mod with `Delta` appended,
94/// and an implementation `impl DeltaStruct<FooDelta> for Foo`.
95///
96/// The delta will have a tuple variant for each method defined for the struct
97/// converted to camel case, and it's tuple will be of the same type as the
98/// argument list of it's respective method (without `&mut self`). It will also
99/// expose delta functions of it's fields.
100///
101/// ## Example:
102///
103/// ```
104/// # use deltastruct_proc::deltastruct;
105/// # use deltastruct::*;
106/// #[deltastruct]
107/// mod Foo {
108/// struct Foo {
109/// x : i32,
110/// y : i32
111/// }
112///
113/// impl Foo {
114/// fn swap(&mut self) {
115/// let tmp = self.x;
116/// self.x = self.y;
117/// self.y = tmp;
118/// }
119///
120/// fn do_stuff(&mut self, n : f64) {
121/// self.x = (n * (self.x as f64)) as i32;
122/// }
123/// }
124/// }
125/// ```
126///
127/// will generate:
128/// ```
129/// # use deltastruct::DeltaStruct;
130/// # struct Foo;
131/// # #[allow(non_camel_case_types)] struct i32Delta;
132/// enum FooDelta {
133/// Swap(),
134/// DoStuff(f64),
135/// X(i32Delta),
136/// Y(i32Delta),
137/// }
138///
139/// impl DeltaStruct<FooDelta> for Foo {
140/// fn apply(&mut self, delta : &FooDelta) {
141/// /* ... */
142/// }
143/// }
144/// ```
145pub use deltastruct_proc::deltastruct;
146
147/// A trait derived for each tagged struct where `T` is it's generated delta.
148///
149/// ```
150/// # use deltastruct::*;
151/// #[deltastruct]
152/// mod Foo {
153/// struct Foo {
154/// bar : bool
155/// }
156/// impl Foo {
157/// fn foobar(&mut self) {}
158/// }
159/// }
160/// ```
161///
162/// will generate:
163/// ```
164/// # use deltastruct::*;
165/// # struct Foo;
166/// # struct FooDelta;
167/// impl DeltaStruct<FooDelta> for Foo {
168/// fn apply(&mut self, delta : &FooDelta) {
169/// /* ... */
170/// }
171/// }
172/// ```
173pub trait DeltaStruct<T> {
174 fn apply(&mut self, delta: &T);
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180
181 #[deltastruct]
182 mod Foo {
183 struct Foo {
184 x: i32,
185 y: i32,
186 }
187
188 impl Foo {
189 pub fn bar(&mut self, a: i64, b: i64) {
190 self.x = ((a * b) as i32) - self.y;
191 }
192
193 pub fn baz(&mut self, data: u32) {
194 self.x += data as i32;
195 self.y -= data as i32;
196 }
197 }
198 }
199
200 #[test]
201 fn self_func() {
202 let mut foo = Foo { x: 4, y: 7 };
203
204 let dfoo = FooDelta::Baz(5);
205 foo.apply(&dfoo);
206
207 assert_eq!(foo.x, 9);
208 assert_eq!(foo.y, 2);
209
210 foo.apply(&dfoo);
211
212 assert_eq!(foo.x, 14);
213 assert_eq!(foo.y, -3);
214
215 let dfoo = FooDelta::Bar(3, 4);
216 foo.apply(&dfoo);
217
218 assert_eq!(foo.x, 15);
219 assert_eq!(foo.y, -3);
220 }
221
222 #[test]
223 fn field_func() {
224 let mut foo = Foo { x: 3, y: 6 };
225
226 let dfoo = FooDelta::X(i32Delta::Set(1));
227 foo.apply(&dfoo);
228
229 assert_eq!(foo.x, 1);
230 assert_eq!(foo.y, 6);
231
232 let dfoo = FooDelta::Y(i32Delta::Set(-20));
233 foo.apply(&dfoo);
234
235 assert_eq!(foo.x, 1);
236 assert_eq!(foo.y, -20);
237 }
238
239 #[test]
240 fn delta_derives() {
241 #[deltastruct(derive(Clone))]
242 mod Testbug {
243 struct Testbug {
244 meh: u8,
245 }
246
247 impl Testbug {
248 fn bar(&mut self) {}
249 }
250 }
251
252 let testbugdelta = TestbugDelta::Bar();
253 testbugdelta.clone();
254 }
255}