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}