1use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
7use ndarray::ScalarOperand;
8use num_traits::{One, Zero};
9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
14pub struct GF2(u8);
15
16impl Zero for GF2 {
17 fn zero() -> GF2 {
18 GF2(0)
19 }
20
21 fn is_zero(&self) -> bool {
22 *self == Self::zero()
23 }
24
25 fn set_zero(&mut self) {
26 *self = Self::zero()
27 }
28}
29
30impl One for GF2 {
31 fn one() -> GF2 {
32 GF2(1)
33 }
34
35 fn set_one(&mut self) {
36 *self = Self::one()
37 }
38
39 fn is_one(&self) -> bool {
40 *self == Self::one()
41 }
42}
43
44impl Add for GF2 {
45 type Output = GF2;
46
47 #[allow(clippy::suspicious_arithmetic_impl)]
48 fn add(self, rhs: GF2) -> GF2 {
49 GF2(self.0 ^ rhs.0)
50 }
51}
52
53impl Sub for GF2 {
54 type Output = GF2;
55
56 #[allow(clippy::suspicious_arithmetic_impl)]
57 fn sub(self, rhs: GF2) -> GF2 {
58 self + rhs
59 }
60}
61
62impl Mul for GF2 {
63 type Output = GF2;
64
65 #[allow(clippy::suspicious_arithmetic_impl)]
66 fn mul(self, rhs: GF2) -> GF2 {
67 GF2(self.0 & rhs.0)
68 }
69}
70
71impl Div for GF2 {
72 type Output = GF2;
73
74 fn div(self, rhs: GF2) -> GF2 {
75 if rhs.is_zero() {
76 panic!("division by zero");
77 }
78 self
79 }
80}
81
82impl std::iter::Sum for GF2 {
83 fn sum<I>(iter: I) -> GF2
84 where
85 I: Iterator<Item = GF2>,
86 {
87 let mut sum = GF2::zero();
88 for a in iter {
89 sum += a;
90 }
91 sum
92 }
93}
94
95macro_rules! impl_ops {
96 ($op:ident, $opmethod:ident, $opassign:ident, $opassign_method:ident) => {
97 impl $op<&GF2> for GF2 {
98 type Output = GF2;
99 fn $opmethod(self, rhs: &GF2) -> GF2 {
100 self.$opmethod(*rhs)
101 }
102 }
103
104 impl $opassign for GF2 {
105 fn $opassign_method(&mut self, rhs: GF2) {
106 *self = self.$opmethod(rhs);
107 }
108 }
109
110 impl $opassign<&GF2> for GF2 {
111 fn $opassign_method(&mut self, rhs: &GF2) {
112 *self = self.$opmethod(*rhs);
113 }
114 }
115 };
116}
117
118impl_ops!(Add, add, AddAssign, add_assign);
119impl_ops!(Sub, sub, SubAssign, sub_assign);
120impl_ops!(Mul, mul, MulAssign, mul_assign);
121impl_ops!(Div, div, DivAssign, div_assign);
122
123impl ScalarOperand for GF2 {}
124
125#[cfg(test)]
126mod test {
127 use super::*;
128
129 #[test]
130 fn ops() {
131 assert_eq!(GF2(0) + GF2(0), GF2(0));
132 assert_eq!(GF2(0) + GF2(1), GF2(1));
133 assert_eq!(GF2(1) + GF2(0), GF2(1));
134 assert_eq!(GF2(1) + GF2(1), GF2(0));
135 assert_eq!(GF2(0) - GF2(0), GF2(0));
136 assert_eq!(GF2(0) - GF2(1), GF2(1));
137 assert_eq!(GF2(1) - GF2(0), GF2(1));
138 assert_eq!(GF2(1) - GF2(1), GF2(0));
139 assert_eq!(GF2(0) * GF2(0), GF2(0));
140 assert_eq!(GF2(0) * GF2(1), GF2(0));
141 assert_eq!(GF2(1) * GF2(0), GF2(0));
142 assert_eq!(GF2(1) * GF2(1), GF2(1));
143 assert_eq!(GF2(0) / GF2(1), GF2(0));
144 assert_eq!(GF2(1) / GF2(1), GF2(1));
145 }
146
147 #[test]
148 #[should_panic]
149 fn div_one_by_zero() {
150 let _a = GF2(1) / GF2(0);
151 }
152
153 #[test]
154 #[should_panic]
155 fn div_zero_by_zero() {
156 let _a = GF2(0) / GF2(0);
157 }
158
159 #[test]
160 fn sum() {
161 assert_eq!([GF2(0), GF2(1), GF2(1)].into_iter().sum::<GF2>(), GF2(0));
162 assert_eq!([GF2(0), GF2(1)].into_iter().sum::<GF2>(), GF2(1));
163 assert_eq!([GF2(1)].into_iter().sum::<GF2>(), GF2(1));
164 assert_eq!([].into_iter().sum::<GF2>(), GF2(0));
165 }
166}