derive_patch/lib.rs
1/*
2 * Copyright (2020) by Marcel Lambert
3 * This project is licensed under the MIT Open Source license.
4 * For more information, see the LICENSE file in this repository.
5 */
6
7//! This crate contains 2 macros.
8//!
9//! One for generating a `partial` Variant of an object. (Inspired by typescript ```Partial<Object>```)
10
11#![deny(missing_docs)]
12
13use proc_macro::TokenStream;
14
15///
16///
17///
18#[proc_macro_derive(HelloWorld)]
19pub fn partial(input: TokenStream) -> TokenStream {
20 input
21}
22
23#[cfg(test)]
24mod tests {
25
26 //#[derive(Partial)]
27 struct Example {
28 foo: f64,
29 bar: Option<String>,
30
31 // #[ignorePartial(default => 42)]
32 // without an default, we cannot provide a `build`. unless the ignored value type is 'default'
33 something_special: u32,
34
35 // #[forcePartial(default => 5)] // we cannot provide a Default trait for the partial, unless default provided, or value type is Default
36 id: u32,
37 }
38
39 #[derive(PartialEq, Default)]
40 // Default: only when nothing forced or the forced values have a default or are default buildable
41 // derives can be customized by user
42 struct PartialExample {
43 foo: Option<f64>,
44 bar: Option<Option<String>>,
45 id: u32, //forced, so not optional
46 }
47
48 impl PartialExample {
49 //only when we have a forced value
50 fn new(id: u32) -> PartialExample {
51 PartialExample {
52 id,
53 //alternatively use ```.. Default::default()``` if present
54 foo: None,
55 bar: None,
56 }
57 }
58
59 fn complete(&self) -> bool {
60 //for each attribute
61 self.foo.is_some() && self.bar.is_some()
62 }
63
64 fn apply(&self, obj: &mut Example) {
65 //for each attribute
66 if let Some(foo) = &self.foo {
67 obj.foo = *foo;
68 }
69 if let Some(bar) = &self.bar {
70 // clone because 'Option' does not implement Copy
71 obj.bar = bar.clone();
72 }
73 }
74
75 /// add all attributes set here in to the given Partial
76 ///
77 /// If an attribute in here is already set in `obj`, then it gets overwritten
78 fn merge_into(&self, obj: &mut PartialExample) {
79 //for each attribute
80 if let Some(foo) = &self.foo {
81 obj.foo = Some(*foo);
82 }
83 if let Some(bar) = &self.bar {
84 obj.bar = Some(bar.clone());
85 }
86 }
87
88 /// check all attributes that are present on BOTH objects, if they are equal.
89 /// If there are no attributes present in both, will return true.
90 fn partial_equal_existing(&self, obj: &PartialExample) -> bool {
91 //for each attribute
92 if let Some(foo) = &self.foo {
93 if let Some(otherfoo) = &obj.foo {
94 if (*foo - *otherfoo).abs() > std::f64::EPSILON {
95 // special comparison for f32 and f64
96 return false;
97 }
98 }
99 }
100
101 if let Some(bar) = &self.bar {
102 if let Some(otherbar) = &obj.bar {
103 if *bar != *otherbar {
104 return false;
105 }
106 }
107 }
108
109 true
110 }
111
112 /// Counts how many attributes are set
113 ///
114 /// Forced values are not counted, as they are always present
115 fn count(&self) -> u32 {
116 let mut count = 0;
117 //for each attribute
118 if self.foo.is_some() {
119 count += 1;
120 }
121
122 if self.bar.is_some() {
123 count += 1;
124 }
125
126 count
127 }
128
129 fn build(&self) -> Result<Example, ()> {
130 if let Some(foo) = &self.foo {
131 if let Some(bar) = &self.bar {
132 return Ok(Example {
133 foo: *foo,
134 bar: bar.clone(),
135 id: self.id,
136 something_special: 42,
137 });
138 }
139 }
140 Err(())
141 }
142 }
143
144 impl PartialEq<Example> for PartialExample {
145 fn eq(&self, other: &Example) -> bool {
146 if let Some(foo) = &self.foo {
147 if other.foo != *foo {
148 return false;
149 }
150 }
151
152 if let Some(bar) = &self.bar {
153 if other.bar != *bar {
154 return false;
155 }
156 }
157
158 true
159 }
160 }
161
162 #[test]
163 fn it_works() {
164 assert_eq!(2 + 2, 4);
165 }
166}