1use core::cmp::Ordering;
2use core::ops::{Add, Sub, Mul, Div, Rem, Shl, Shr};
3use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, ShlAssign, ShrAssign};
4
5use crate::ByteUnit;
6
7impl<T: Into<ByteUnit>> Add<T> for ByteUnit {
8 type Output = Self;
9
10 #[inline(always)]
11 fn add(self, rhs: T) -> Self::Output {
12 ByteUnit(self.0.saturating_add(rhs.into().0))
13 }
14}
15
16impl<T: Into<ByteUnit>> Sub<T> for ByteUnit {
17 type Output = Self;
18
19 #[inline(always)]
20 fn sub(self, rhs: T) -> Self::Output {
21 ByteUnit(self.0.saturating_sub(rhs.into().0))
22 }
23}
24
25impl<T: Into<ByteUnit>> Mul<T> for ByteUnit {
26 type Output = Self;
27
28 #[inline(always)]
29 fn mul(self, rhs: T) -> Self::Output {
30 ByteUnit(self.0.saturating_mul(rhs.into().0))
31 }
32}
33
34impl<T: Into<ByteUnit>> Div<T> for ByteUnit {
35 type Output = Self;
36
37 #[inline(always)]
38 fn div(self, rhs: T) -> Self::Output {
39 let value = rhs.into().0;
40 match value {
41 0 => ByteUnit::max_value(),
42 _ => ByteUnit(self.0 / value)
43 }
44 }
45}
46
47impl<T: Into<ByteUnit>> Rem<T> for ByteUnit {
48 type Output = Self;
49
50 #[inline(always)]
51 fn rem(self, rhs: T) -> Self::Output {
52 let value = rhs.into().0;
53 match value {
54 0 => ByteUnit(0),
55 _ => ByteUnit(self.0 % value)
56 }
57 }
58}
59
60impl<T: Into<ByteUnit>> Shl<T> for ByteUnit {
61 type Output = Self;
62 fn shl(self, rhs: T) -> Self::Output {
63 let wanted = rhs.into().0;
64 let available = self.0.leading_zeros() as u64;
65 if wanted > available {
66 ByteUnit::max_value()
67 } else {
68 ByteUnit(self.0 << wanted)
69 }
70 }
71}
72
73impl<T: Into<ByteUnit>> Shr<T> for ByteUnit {
74 type Output = Self;
75 fn shr(self, rhs: T) -> Self::Output {
76 ByteUnit(self.0 >> rhs.into().0)
77 }
78}
79
80impl<T: Into<ByteUnit> + Copy> PartialEq<T> for ByteUnit {
81 fn eq(&self, other: &T) -> bool {
82 self.0 == (*other).into().0
83 }
84}
85
86impl<T: Into<ByteUnit> + Copy> PartialOrd<T> for ByteUnit {
87 fn partial_cmp(&self, other: &T) -> Option<Ordering> {
88 self.0.partial_cmp(&(*other).into().0)
89 }
90}
91
92macro_rules! impl_self_assign_op {
93 ($Trait:ident, $func:ident, $op:tt) => (
94 impl<T: Into<ByteUnit>> $Trait<T> for ByteUnit {
95 #[inline(always)]
96 fn $func(&mut self, rhs: T) {
97 *self = *self $op rhs.into();
98 }
99 }
100 )
101}
102
103impl_self_assign_op!(AddAssign, add_assign, +);
104impl_self_assign_op!(SubAssign, sub_assign, -);
105impl_self_assign_op!(MulAssign, mul_assign, *);
106impl_self_assign_op!(DivAssign, div_assign, /);
107impl_self_assign_op!(RemAssign, rem_assign, %);
108impl_self_assign_op!(ShrAssign, shr_assign, >>);
109impl_self_assign_op!(ShlAssign, shl_assign, <<);
110
111macro_rules! impl_arith_op_on_core_type {
112 ($T:ident, $Trait:ident, $func:ident, $op:tt) => (
113 impl $Trait<ByteUnit> for $T {
114 type Output = ByteUnit;
115
116 #[inline(always)]
117 fn $func(self, rhs: ByteUnit) -> Self::Output {
118 ByteUnit::from(self) $op rhs
119 }
120 }
121 )
122}
123
124macro_rules! impl_arith_ops_on_core {
125 ($T:ident) => (
126 impl_arith_op_on_core_type!($T, Add, add, +);
127 impl_arith_op_on_core_type!($T, Sub, sub, -);
128 impl_arith_op_on_core_type!($T, Mul, mul, *);
129 impl_arith_op_on_core_type!($T, Div, div, /);
130 impl_arith_op_on_core_type!($T, Rem, rem, %);
131 impl_arith_op_on_core_type!($T, Shl, shl, <<);
132 impl_arith_op_on_core_type!($T, Shr, shr, >>);
133
134 impl PartialEq<ByteUnit> for $T {
135 #[inline(always)]
136 fn eq(&self, other: &ByteUnit) -> bool {
137 ByteUnit::from(*self).eq(other)
138 }
139 }
140
141 impl PartialOrd<ByteUnit> for $T {
142 #[inline(always)]
143 fn partial_cmp(&self, other: &ByteUnit) -> Option<Ordering> {
144 ByteUnit::from(*self).partial_cmp(other)
145 }
146 }
147 )
148}
149
150impl_arith_ops_on_core!(usize);
151impl_arith_ops_on_core!(u8);
152impl_arith_ops_on_core!(u16);
153impl_arith_ops_on_core!(u32);
154impl_arith_ops_on_core!(u64);
155impl_arith_ops_on_core!(u128);
156
157impl_arith_ops_on_core!(isize);
158impl_arith_ops_on_core!(i8);
159impl_arith_ops_on_core!(i16);
160impl_arith_ops_on_core!(i32);
161impl_arith_ops_on_core!(i64);
162impl_arith_ops_on_core!(i128);
163
164#[cfg(test)]
165mod tests {
166 use crate::{ByteUnit, ToByteUnit};
167
168 #[test]
169 fn test_saturation() {
170 assert_eq!(ByteUnit::B * -1, 0);
171 assert_eq!(ByteUnit::B * -3, 0);
172 assert_eq!(ByteUnit::B / -3, ByteUnit::max_value());
173 assert_eq!(ByteUnit::B - 100, 0);
174 assert_eq!((100 * ByteUnit::B) % -10, 0);
175
176 assert_eq!(ByteUnit::B + (-100i32), 1);
178 assert_eq!(-100 + ByteUnit::B, 1);
179 }
180
181 #[test]
182 fn test_core_types_operations() {
183 assert_eq!(1000 - 300.bytes(), 700);
184 assert_eq!(1024 >> 2.bytes(), 256);
185 assert_eq!(2 << 2.bytes(), 8);
186 assert_eq!(2048 / 4.bytes(), 512);
187 assert!((500 + 700) < 2.mebibytes());
188 assert!((500 + 700) > 2.bytes());
189 }
190
191 #[test]
192 fn test_add_assign_op() {
193 let mut b = 0.bytes();
194 b += 10;
195 assert_eq!(b, 10);
196
197 let mut b = 10.bytes();
198 b *= 100.kibibytes();
199 assert_eq!(b, 1024.kilobytes());
200 }
201}