summaryrefslogtreecommitdiffstats
path: root/third_party/rust/derive_more-impl/doc/add.md
blob: 5d58996a28ac5716ffa7cc07acc6906f67517a47 (plain)
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
# What `#[derive(Add)]` generates

The derived `Add` implementation will allow two structs from the same type to be
added together. This done by adding their respective fields together and
creating a new struct with those values.
For enums each variant can be added in a similar way to another instance of that
same variant. There's one big difference however, it returns a
`Result<EnumType>`, because an error is returned when to different variants are
added together.




## Tuple structs

When deriving `Add` for a tuple struct with two fields like this:

```rust
# use derive_more::Add;
#
#[derive(Add)]
struct MyInts(i32, i32);
```

Code like this will be generated:

```rust
# struct MyInts(i32, i32);
impl ::core::ops::Add for MyInts {
    type Output = MyInts;
    fn add(self, rhs: MyInts) -> MyInts {
        MyInts(self.0.add(rhs.0), self.1.add(rhs.1))
    }
}
```

The behaviour is similar with more or less fields.




## Regular structs

When deriving `Add` for a regular struct with two fields like this:

```rust
# use derive_more::Add;
#
#[derive(Add)]
struct Point2D {
    x: i32,
    y: i32,
}
```

Code like this will be generated:

```rust
# struct Point2D {
#     x: i32,
#     y: i32,
# }
impl ::core::ops::Add for Point2D {
    type Output = Point2D;
    fn add(self, rhs: Point2D) -> Point2D {
        Point2D {
            x: self.x.add(rhs.x),
            y: self.y.add(rhs.y),
        }
    }
}
```

The behaviour is similar for more or less fields.




## Enums

There's a big difference between the code that is generated for the two struct
types and the one that is generated for enums. The code for enums returns
`Result<EnumType>` instead of an `EnumType` itself. This is because adding an
enum to another enum is only possible if both are the same variant. This makes
the generated code much more complex as well, because this check needs to be
done. For instance when deriving `Add` for an enum like this:

```rust
# use derive_more::Add;
#
#[derive(Add)]
enum MixedInts {
    SmallInt(i32),
    BigInt(i64),
    TwoSmallInts(i32, i32),
    NamedSmallInts { x: i32, y: i32 },
    UnsignedOne(u32),
    UnsignedTwo(u32),
    Unit,
}
```

Code like this will be generated:

```rust
# enum MixedInts {
#     SmallInt(i32),
#     BigInt(i64),
#     TwoSmallInts(i32, i32),
#     NamedSmallInts { x: i32, y: i32 },
#     UnsignedOne(u32),
#     UnsignedTwo(u32),
#     Unit,
# }
impl ::core::ops::Add for MixedInts {
    type Output = Result<MixedInts, ::derive_more::ops::BinaryError>;
    fn add(self, rhs: MixedInts) -> Result<MixedInts, ::derive_more::ops::BinaryError> {
        match (self, rhs) {
            (MixedInts::SmallInt(__l_0), MixedInts::SmallInt(__r_0)) => {
                Ok(MixedInts::SmallInt(__l_0.add(__r_0)))
            }
            (MixedInts::BigInt(__l_0), MixedInts::BigInt(__r_0)) => {
                Ok(MixedInts::BigInt(__l_0.add(__r_0)))
            }
            (MixedInts::TwoSmallInts(__l_0, __l_1), MixedInts::TwoSmallInts(__r_0, __r_1)) => {
                Ok(MixedInts::TwoSmallInts(__l_0.add(__r_0), __l_1.add(__r_1)))
            }
            (MixedInts::NamedSmallInts { x: __l_0, y: __l_1 },
             MixedInts::NamedSmallInts { x: __r_0, y: __r_1 }) => {
                Ok(MixedInts::NamedSmallInts {
                    x: __l_0.add(__r_0),
                    y: __l_1.add(__r_1),
                })
            }
            (MixedInts::UnsignedOne(__l_0), MixedInts::UnsignedOne(__r_0)) => {
                Ok(MixedInts::UnsignedOne(__l_0.add(__r_0)))
            }
            (MixedInts::UnsignedTwo(__l_0), MixedInts::UnsignedTwo(__r_0)) => {
                Ok(MixedInts::UnsignedTwo(__l_0.add(__r_0)))
            }
            (MixedInts::Unit, MixedInts::Unit) => Err(::derive_more::ops::BinaryError::Unit(
                ::derive_more::ops::UnitError::new("add"),
            )),
            _ => Err(::derive_more::ops::BinaryError::Mismatch(
                ::derive_more::ops::WrongVariantError::new("add"),
            )),
        }
    }
}
```

Also note the Unit type that throws an error when adding it to itself.