1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * Copyright (2020) by Marcel Lambert
 * This project is licensed under the MIT Open Source license.
 * For more information, see the LICENSE file in this repository.
 */

//! This crate contains 2 macros.
//!
//! One for generating a `partial` Variant of an object. (Inspired by typescript ```Partial<Object>```)

#![deny(missing_docs)]

use proc_macro::TokenStream;

///
///
///
#[proc_macro_derive(HelloWorld)]
pub fn partial(input: TokenStream) -> TokenStream {
    input
}

#[cfg(test)]
mod tests {

    //#[derive(Partial)]
    struct Example {
        foo: f64,
        bar: Option<String>,

        // #[ignorePartial(default => 42)]
        // without an default, we cannot provide a `build`. unless the ignored value type is 'default'
        something_special: u32,

        // #[forcePartial(default => 5)] // we cannot provide a Default trait for the partial, unless default provided, or value type is Default
        id: u32,
    }

    #[derive(PartialEq, Default)]
    // Default: only when nothing forced or the forced values have a default or are default buildable
    // derives can be customized by user
    struct PartialExample {
        foo: Option<f64>,
        bar: Option<Option<String>>,
        id: u32, //forced, so not optional
    }

    impl PartialExample {
        //only when we have a forced value
        fn new(id: u32) -> PartialExample {
            PartialExample {
                id,
                //alternatively use ```.. Default::default()``` if present
                foo: None,
                bar: None,
            }
        }

        fn complete(&self) -> bool {
            //for each attribute
            self.foo.is_some() && self.bar.is_some()
        }

        fn apply(&self, obj: &mut Example) {
            //for each attribute
            if let Some(foo) = &self.foo {
                obj.foo = *foo;
            }
            if let Some(bar) = &self.bar {
                // clone because 'Option' does not implement Copy
                obj.bar = bar.clone();
            }
        }

        /// add all attributes set here in to the given Partial
        ///
        /// If an attribute in here is already set in `obj`, then it gets overwritten
        fn merge_into(&self, obj: &mut PartialExample) {
            //for each attribute
            if let Some(foo) = &self.foo {
                obj.foo = Some(*foo);
            }
            if let Some(bar) = &self.bar {
                obj.bar = Some(bar.clone());
            }
        }

        /// check all attributes that are present on BOTH objects, if they are equal.
        /// If there are no attributes present in both, will return true.
        fn partial_equal_existing(&self, obj: &PartialExample) -> bool {
            //for each attribute
            if let Some(foo) = &self.foo {
                if let Some(otherfoo) = &obj.foo {
                    if (*foo - *otherfoo).abs() > std::f64::EPSILON {
                        // special comparison for f32 and f64
                        return false;
                    }
                }
            }

            if let Some(bar) = &self.bar {
                if let Some(otherbar) = &obj.bar {
                    if *bar != *otherbar {
                        return false;
                    }
                }
            }

            true
        }

        /// Counts how many attributes are set
        ///
        /// Forced values are not counted, as they are always present
        fn count(&self) -> u32 {
            let mut count = 0;
            //for each attribute
            if self.foo.is_some() {
                count += 1;
            }

            if self.bar.is_some() {
                count += 1;
            }

            count
        }

        fn build(&self) -> Result<Example, ()> {
            if let Some(foo) = &self.foo {
                if let Some(bar) = &self.bar {
                    return Ok(Example {
                        foo: *foo,
                        bar: bar.clone(),
                        id: self.id,
                        something_special: 42,
                    });
                }
            }
            Err(())
        }
    }

    impl PartialEq<Example> for PartialExample {
        fn eq(&self, other: &Example) -> bool {
            if let Some(foo) = &self.foo {
                if other.foo != *foo {
                    return false;
                }
            }

            if let Some(bar) = &self.bar {
                if other.bar != *bar {
                    return false;
                }
            }

            true
        }
    }

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}