1use std::ops::{Add, Sub};
2
3use crate::*;
4
5impl<const A: u8, const B: u8> PaddedNumber<A, B> {
6 pub fn wrapping_add(self, rhs: u64) -> Self {
25 self.add_impl(rhs, |new_number, max_for_length_number| {
26 let start = Self::min_number_for_min_length();
27
28 match B == 0 {
29 true => start,
30 false => start.wrapping_add(new_number - max_for_length_number - 1),
32 }
33 })
34 }
35
36 pub fn saturating_add(self, rhs: u64) -> Self {
48 self.add_impl(rhs, |_new_number, max_for_length_number| Self {
49 leading_zeros: 0,
50 number: max_for_length_number,
51 })
52 }
53
54 pub fn wrapping_sub(self, rhs: u64) -> Self {
73 self.sub_impl(rhs, |remaining_difference| {
74 Self::max_number_for_max_length().wrapping_sub(remaining_difference)
75 })
76 }
77
78 pub fn saturating_sub(self, rhs: u64) -> Self {
90 self.sub_impl(rhs, |_| Self::min_number_for_min_length())
91 }
92
93 fn add_impl(self, rhs: u64, overflow_fn: fn(u64, u64) -> Self) -> Self {
95 if rhs == 0 {
96 return self;
97 }
98
99 let new_number = self.number + rhs;
100
101 let max_for_length = self.max_number_for_current_length();
102 let max_for_length_number = max_for_length.number;
103
104 if new_number > max_for_length_number {
106 if self.len() == B {
108 overflow_fn(new_number, max_for_length_number)
109 }
110 else {
112 let next_number = Self { leading_zeros: self.len() + 1, number: 0 };
113
114 let diff_to_next_increase = max_for_length_number - self.number;
115 let rhs_next = rhs - diff_to_next_increase - 1;
116
117 next_number.add_impl(rhs_next, overflow_fn)
118 }
119 }
120 else {
122 let new_number_digits = digit_length(new_number);
123 let current_digits = digit_length(self.number);
124 let leading_zeroes_to_remove = new_number_digits - current_digits;
125
126 Self {
127 leading_zeros: self.leading_zeros - leading_zeroes_to_remove,
128 number: new_number,
129 }
130 }
131 }
132
133 fn sub_impl(self, rhs: u64, overflow_fn: impl FnOnce(u64) -> Self) -> Self {
134 if rhs == 0 || self.is_empty() {
135 return self;
136 }
137
138 match self.number.checked_sub(rhs) {
139 Some(new_number) => {
141 let current_digits = digit_length(self.number);
142 let new_number_digits = digit_length(new_number);
143 let leading_zeroes_to_add = current_digits - new_number_digits;
144
145 Self {
146 leading_zeros: self.leading_zeros + leading_zeroes_to_add,
147 number: new_number,
148 }
149 }
150 None => {
152 let length = self.len();
153
154 if length == A {
155 overflow_fn(rhs - self.number - 1)
157 } else {
158 let next_number =
159 PaddedNumber { leading_zeros: 0, number: Self::max_number_for_length_impl(length - 1) };
160
161 let overflow_diff = rhs - self.number;
162 let next_rhs = overflow_diff - 1;
163
164 next_number.sub_impl(next_rhs, overflow_fn)
165 }
166 }
167 }
168 }
169
170 const fn max_number_for_current_length(&self) -> PaddedNumber<A, B> {
171 PaddedNumber { leading_zeros: 0, number: Self::max_number_for_length_impl(self.len()) }
172 }
173
174 const fn max_number_for_max_length() -> PaddedNumber<A, B> {
175 PaddedNumber { leading_zeros: 0, number: Self::max_number_for_length_impl(B) }
176 }
177
178 const fn min_number_for_min_length() -> Self {
179 Self { leading_zeros: A, number: 0 }
180 }
181
182 const fn max_number_for_length_impl(length: u8) -> u64 {
183 (10_u64.pow(length as u32)) - 1
184 }
185}
186
187impl<const A: u8, const B: u8> Add<u64> for PaddedNumber<A, B> {
188 type Output = Self;
189
190 fn add(self, rhs: u64) -> Self::Output {
191 Self::wrapping_add(self, rhs)
192 }
193}
194
195impl<const A: u8, const B: u8> Sub<u64> for PaddedNumber<A, B> {
196 type Output = Self;
197
198 fn sub(self, rhs: u64) -> Self::Output {
199 Self::wrapping_sub(self, rhs)
200 }
201}
202
203const fn digit_length(n: u64) -> u8 {
204 if n == 0 {
205 0
206 } else {
207 let mut count = 1;
208 let mut current = n;
209
210 while current >= 10 {
211 count += 1;
212 current /= 10
213 }
214
215 count
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use crate::{tests::mock_from_str, *};
222
223 #[test]
224 fn max_number_for_current_length() {
225 assert_impl("", "");
226 assert_impl("9", "0");
227 assert_impl("99", "00");
228 assert_impl("999", "001");
229 assert_impl("9999", "1234");
230
231 fn assert_impl(max_number_str: &str, number_str: &str) {
232 let expected_max_number = mock_from_str::<0, 10>(max_number_str);
233 let actual_max_number = mock_from_str::<0, 10>(number_str).max_number_for_current_length();
234 assert_eq!(expected_max_number, actual_max_number);
235 }
236 }
237
238 #[test]
239 fn max_number_for_max_length() {
240 assert_impl::<0>("");
241 assert_impl::<1>("9");
242 assert_impl::<2>("99");
243
244 fn assert_impl<const B: u8>(expected_max_number_str: &str) {
245 let expected_max_number = mock_from_str::<0, B>(expected_max_number_str);
246 let actual_max_number = PaddedNumber::<0, B>::max_number_for_max_length();
247 assert_eq!(expected_max_number, actual_max_number);
248 }
249 }
250
251 #[test]
252 fn non_overflowing_add() {
253 assert_non_overflowing_add("00", ("00", 0));
255
256 assert_non_overflowing_add("0", ("", 1));
258
259 assert_non_overflowing_add("00", ("9", 1));
261 assert_non_overflowing_add("0000", ("999", 1));
262 assert_non_overflowing_add("000", ("9", 101));
263
264 assert_non_overflowing_add("99", ("00", 99));
266 assert_non_overflowing_add("001", ("000", 1));
267 assert_non_overflowing_add("100", ("099", 1));
268 assert_non_overflowing_add("1099", ("0099", 1000));
269
270 fn assert_non_overflowing_add(expected: &str, (lhs, rhs): (&str, u64)) {
271 assert_arithmetic::<0, 10>(expected, (lhs, rhs), |lhs, rhs| {
272 lhs.add_impl(rhs, |_, _| panic!("overflow occurred when testing non overflows"))
273 });
274 }
275 }
276
277 #[test]
278 fn wrapping_add() {
279 assert_wrapping_add::<0, 10>("", ("9999999999", 1));
281 assert_wrapping_add::<2, 10>("00", ("9999999999", 1));
283 assert_wrapping_add::<1, 10>("01", ("9999999900", 111));
285 assert_wrapping_add::<0, 0>("", ("", 10));
287
288 fn assert_wrapping_add<const A: u8, const B: u8>(expected: &str, (lhs, rhs): (&str, u64)) {
289 assert_arithmetic(expected, (lhs, rhs), PaddedNumber::<A, B>::wrapping_add);
290 }
291 }
292
293 #[test]
294 fn saturating_add() {
295 assert_saturating_add::<0, 10>("9999999999", ("9999999999", 1));
297 assert_saturating_add::<0, 10>("9999999999", ("9999999900", 1000));
299 assert_saturating_add::<0, 0>("", ("", 10));
301
302 assert_saturating_add::<0, 10>("9999999992", ("9999999990", 2));
304
305 fn assert_saturating_add<const A: u8, const B: u8>(expected: &str, (lhs, rhs): (&str, u64)) {
306 assert_arithmetic(expected, (lhs, rhs), PaddedNumber::<A, B>::saturating_add);
307 }
308 }
309
310 #[test]
311 fn non_overflowing_sub() {
312 assert_non_overflowing_sub("00", ("00", 0));
314
315 assert_non_overflowing_sub("0", ("9", 9));
317 assert_non_overflowing_sub("0000", ("0100", 100));
318 assert_non_overflowing_sub("099", ("100", 1));
319 assert_non_overflowing_sub("050", ("100", 50));
320
321 assert_non_overflowing_sub("", ("0", 1));
323 assert_non_overflowing_sub("9", ("00", 1));
324 assert_non_overflowing_sub("09", ("090", 181));
325 assert_non_overflowing_sub("999", ("0100", 101));
326 assert_non_overflowing_sub("995", ("0100", 105));
327
328 fn assert_non_overflowing_sub(expected: &str, (lhs, rhs): (&str, u64)) {
329 assert_arithmetic::<0, 10>(expected, (lhs, rhs), |lhs, rhs| {
330 lhs.sub_impl(rhs, |_| panic!("overflow occurred when testing non overflows"))
331 });
332 }
333 }
334
335 #[test]
336 fn wrapping_sub() {
337 assert_wrapping_sub::<1, 1>("9", ("0", 1));
339 assert_wrapping_sub::<1, 3>("999", ("0", 1));
341 assert_wrapping_sub::<1, 3>("995", ("01", 16));
343 assert_wrapping_sub::<0, 0>("", ("", 10));
345
346 fn assert_wrapping_sub<const A: u8, const B: u8>(expected: &str, (lhs, rhs): (&str, u64)) {
347 assert_arithmetic(expected, (lhs, rhs), PaddedNumber::<A, B>::wrapping_sub);
348 }
349 }
350
351 #[test]
352 fn saturating_sub() {
353 assert_saturating_sub::<1, 1>("0", ("0", 1));
355 assert_saturating_sub::<2, 2>("00", ("00", 1));
356 assert_saturating_sub::<0, 2>("", ("00", 1000));
358 assert_saturating_sub::<1, 2>("0", ("00", 1000));
359 assert_saturating_sub::<1, 2>("0", ("90", 1000));
360 assert_saturating_sub::<1, 2>("0", ("99", 1000));
361
362 fn assert_saturating_sub<const A: u8, const B: u8>(expected: &str, (lhs, rhs): (&str, u64)) {
363 assert_arithmetic(expected, (lhs, rhs), PaddedNumber::<A, B>::saturating_sub);
364 }
365 }
366
367 fn assert_arithmetic<const A: u8, const B: u8>(
368 expected: &str,
369 (lhs, rhs): (&str, u64),
370 operator: impl Fn(PaddedNumber<A, B>, u64) -> PaddedNumber<A, B>,
371 ) {
372 let expected = mock_from_str::<A, B>(expected);
373 let actual = operator(mock_from_str::<A, B>(lhs), rhs);
374 assert_eq!(
375 expected, actual,
376 "failed to operate on '{}' with {} to in the end expect '{}'",
377 lhs, rhs, expected
378 );
379 }
380}