range_set_blaze/
integer.rs

1use crate::UIntPlusOne;
2#[cfg(feature = "from_slice")]
3use crate::{RangeSetBlaze, from_slice::FromSliceIter};
4use core::hash::Hash;
5use core::net::{Ipv4Addr, Ipv6Addr};
6use core::ops::{AddAssign, SubAssign};
7use core::panic;
8use core::{fmt, ops::RangeInclusive};
9use num_traits::ops::overflowing::OverflowingSub;
10
11#[cfg(feature = "from_slice")]
12#[allow(clippy::redundant_pub_crate)]
13pub(crate) const LANES: usize = 16;
14
15#[allow(unused_imports)]
16use num_traits::Zero;
17
18/// Represents elements that can be used within [`RangeSetBlaze`] and as keys in [`RangeMapBlaze`].
19///
20/// This includes integer types from `u8` to `u128` (including `usize`), `i8` to `i128` (including `isize`),
21/// as well as `char`, `Ipv4Addr`, and `Ipv6Addr`.
22///
23/// [`RangeSetBlaze`]: crate::RangeSetBlaze
24/// [`RangeMapBlaze`]: crate::RangeMapBlaze
25pub trait Integer: Copy + PartialEq + PartialOrd + Ord + fmt::Debug + Send + Sync {
26    /// Attempts to add one to the current value, returning `None` if the operation would overflow.
27    fn checked_add_one(self) -> Option<Self>;
28
29    /// Adds one to the current value, panicking in debug mode if the operation overflows.
30    ///
31    /// # Examples
32    /// ```
33    /// use range_set_blaze::Integer;
34    ///
35    /// assert_eq!(5u8.add_one(), 6);
36    /// ```
37    #[must_use]
38    fn add_one(self) -> Self;
39
40    /// Subtracts one from the current value, panicking in debug mode if the operation underflows.
41    ///
42    /// # Examples
43    /// ```
44    /// use range_set_blaze::Integer;
45    ///
46    /// assert_eq!(5u8.sub_one(), 4);
47    /// ```
48    #[must_use]
49    fn sub_one(self) -> Self;
50
51    /// Subtracts one from the current value and assigns it back to `self`.
52    fn assign_sub_one(&mut self);
53
54    /// Returns an exhausted range, which is a range that starts from the maximum value and ends at the minimum value.
55    /// This results in an empty range.
56    ///
57    /// # Examples
58    /// ```
59    /// use range_set_blaze::Integer;
60    ///
61    /// let range = u8::exhausted_range();
62    /// assert!(range.is_empty());
63    /// ```
64    #[must_use]
65    fn exhausted_range() -> RangeInclusive<Self> {
66        Self::max_value()..=Self::min_value()
67    }
68
69    /// Advances the iterator for the given range by one step, returning the next value or `None` if the range is exhausted.
70    ///
71    /// This method needs to be defined on each type of interest because the `core::Step` trait is not stable yet.
72    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self>;
73
74    /// Advances the iterator for the given range in reverse by one step, returning the previous value or `None` if the range is exhausted.
75    ///
76    /// This method needs to be defined on each type of interest because the `core::Step` trait is not stable yet.
77    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self>;
78
79    /// Returns the minimum value that can be represented by the type.
80    ///
81    /// # Examples
82    /// ```
83    /// use range_set_blaze::Integer;
84    ///
85    /// assert_eq!(u8::min_value(), 0);
86    /// ```
87    #[must_use]
88    fn min_value() -> Self;
89
90    /// Returns the maximum value that can be represented by the type.
91    ///
92    /// # Examples
93    /// ```
94    /// use range_set_blaze::Integer;
95    ///
96    /// assert_eq!(u8::max_value(), 255);
97    /// ```
98    #[must_use]
99    fn max_value() -> Self;
100
101    #[cfg(feature = "from_slice")]
102    /// Creates a [`RangeSetBlaze`] from a slice, specific to the integer type.
103    ///
104    /// [`RangeSetBlaze`]: crate::RangeSetBlaze
105    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self>;
106
107    /// The type representing the safe length for a [`RangeSetBlaze`]. For example, the length of a `RangeSetBlaze<u8>` is `u16` to handle ranges up to 256 elements.
108    /// For larger types like `u128`, this is represented by a custom type `UIntPlusOne<u128>`.
109    ///
110    /// [`RangeSetBlaze`]: crate::RangeSetBlaze
111    ///
112    /// # Examples
113    /// ```
114    /// use range_set_blaze::{RangeSetBlaze, Integer};
115    ///
116    /// let len: <u8 as Integer>::SafeLen = RangeSetBlaze::from_iter([0u8..=255]).len();
117    /// assert_eq!(len, 256);
118    /// ```
119    type SafeLen: Hash
120        + Copy
121        + PartialEq
122        + PartialOrd
123        + num_traits::Zero
124        + num_traits::One
125        + AddAssign
126        + SubAssign;
127
128    /// Calculates the length of a range without overflow.
129    ///
130    /// # Examples
131    /// ```
132    /// use range_set_blaze::Integer;
133    ///
134    /// assert_eq!(<u8 as Integer>::safe_len(&(0..=255)), 256);
135    /// ```
136    fn safe_len(range: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen;
137
138    // FUTURE define .len() SortedDisjoint
139
140    /// Converts a `f64` to [`Integer::SafeLen`] using the formula `f as Self::SafeLen`. For large integer types, this will result in a loss of precision.
141    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen;
142
143    /// Converts [`Integer::SafeLen`] to `f64`, potentially losing precision for large values.
144    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64;
145
146    /// Computes `self + (b - 1)` where `b` is of type [`Integer::SafeLen`].
147    #[must_use]
148    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self;
149
150    /// Computes `self - (b - 1)` where `b` is of type [`Integer::SafeLen`].
151    #[must_use]
152    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self;
153}
154
155/// Macro to implement the `Integer` trait for specific integer types.
156macro_rules! impl_integer_ops {
157    ($type:ty, $type2:ty) => {
158        #[inline]
159        fn checked_add_one(self) -> Option<Self> {
160            self.checked_add(1)
161        }
162
163        #[inline]
164        fn add_one(self) -> Self {
165            self + 1
166        }
167
168        #[inline]
169        fn sub_one(self) -> Self {
170            self - 1
171        }
172
173        #[inline]
174        fn assign_sub_one(&mut self) {
175            *self -= 1;
176        }
177
178        #[inline]
179        fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
180            range.next()
181        }
182
183        #[inline]
184        fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
185            range.next_back()
186        }
187
188        #[inline]
189        fn min_value() -> Self {
190            Self::MIN
191        }
192
193        #[inline]
194        fn max_value() -> Self {
195            Self::MAX
196        }
197
198        #[cfg(feature = "from_slice")]
199        #[inline]
200        fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
201            FromSliceIter::<Self, LANES>::new(slice.as_ref()).collect()
202        }
203
204        #[allow(clippy::cast_sign_loss)]
205        fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
206            // 1️⃣ Contract: caller promises start ≤ end  (checked only in debug builds)
207            debug_assert!(r.start() <= r.end(), "start ≤ end required");
208
209            // 2️⃣ Compute distance in `Self` then reinterpret‑cast to the first
210            //     widening type `$type2` (loss‑free under the invariant above).
211            let delta_wide: $type2 = r.end().overflowing_sub(r.start()).0 as $type2;
212
213            // 3️⃣ Final widening to `SafeLen`.
214            //    `try_from` is infallible here, so LLVM removes the check in release.
215            <<Self as Integer>::SafeLen>::try_from(delta_wide)
216                .expect("$type2 ⊆ SafeLen; optimizer drops this in release")
217                + 1 // 4️⃣ Inclusive length = distance + 1
218        }
219
220        #[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
221        fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
222            len as f64
223        }
224
225        #[allow(clippy::cast_sign_loss)]
226        #[allow(clippy::cast_precision_loss)]
227        #[allow(clippy::cast_possible_truncation)]
228        fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
229            f as Self::SafeLen
230        }
231
232        #[allow(clippy::cast_possible_truncation)]
233        #[allow(clippy::cast_possible_wrap)]
234        fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
235            #[cfg(debug_assertions)]
236            {
237                let max_len = Self::safe_len(&(self..=Self::MAX));
238                assert!(
239                    b > 0 && b <= max_len,
240                    "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
241                );
242            }
243            // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
244            self.wrapping_add((b - 1) as Self)
245        }
246
247        #[allow(clippy::cast_possible_truncation)]
248        #[allow(clippy::cast_possible_wrap)]
249        fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
250            #[cfg(debug_assertions)]
251            {
252                let max_len = Self::safe_len(&(Self::MIN..=self));
253                assert!(
254                    0 < b && b <= max_len,
255                    "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
256                );
257            }
258            // If b is in range, two’s-complement wrap-around yields the correct start even if the sub overflows
259            self.wrapping_sub((b - 1) as Self)
260        }
261    };
262}
263
264impl Integer for i8 {
265    type SafeLen = u16;
266    impl_integer_ops!(i8, u8);
267}
268
269impl Integer for u8 {
270    type SafeLen = u16;
271    impl_integer_ops!(u8, Self);
272}
273
274impl Integer for i32 {
275    type SafeLen = u64;
276
277    impl_integer_ops!(i32, u32);
278}
279
280impl Integer for u32 {
281    type SafeLen = u64;
282
283    impl_integer_ops!(u32, Self);
284}
285
286impl Integer for i64 {
287    type SafeLen = u128;
288
289    impl_integer_ops!(i64, u64);
290}
291
292impl Integer for u64 {
293    type SafeLen = u128;
294
295    impl_integer_ops!(u64, Self);
296}
297
298impl Integer for i128 {
299    type SafeLen = UIntPlusOne<u128>;
300
301    #[inline]
302    fn checked_add_one(self) -> Option<Self> {
303        self.checked_add(1)
304    }
305
306    #[inline]
307    fn add_one(self) -> Self {
308        self + 1
309    }
310
311    #[inline]
312    fn sub_one(self) -> Self {
313        self - 1
314    }
315
316    #[inline]
317    fn assign_sub_one(&mut self) {
318        *self -= 1;
319    }
320
321    #[inline]
322    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
323        range.next()
324    }
325
326    #[inline]
327    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
328        range.next_back()
329    }
330
331    #[inline]
332    fn min_value() -> Self {
333        Self::MIN
334    }
335
336    #[inline]
337    fn max_value() -> Self {
338        Self::MAX
339    }
340
341    #[cfg(feature = "from_slice")]
342    #[inline]
343    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
344        RangeSetBlaze::from_iter(slice.as_ref())
345    }
346
347    #[allow(clippy::cast_sign_loss)]
348    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
349        debug_assert!(r.start() <= r.end());
350        // Signed sub may overflow, but casting preserves correct unsigned distance
351        let less1 = r.end().overflowing_sub(r.start()).0 as u128;
352        let less1 = UIntPlusOne::UInt(less1);
353        less1 + UIntPlusOne::UInt(1)
354    }
355
356    #[allow(clippy::cast_precision_loss)]
357    #[allow(clippy::cast_possible_truncation)]
358    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
359        match len {
360            UIntPlusOne::UInt(v) => v as f64,
361            UIntPlusOne::MaxPlusOne => UIntPlusOne::<u128>::max_plus_one_as_f64(),
362        }
363    }
364
365    #[allow(clippy::cast_sign_loss)]
366    #[allow(clippy::cast_possible_truncation)]
367    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
368        if f >= UIntPlusOne::<u128>::max_plus_one_as_f64() {
369            UIntPlusOne::MaxPlusOne
370        } else {
371            UIntPlusOne::UInt(f as u128)
372        }
373    }
374
375    /// Computes the inclusive end of a range starting at `self` with length `b`,
376    /// by returning `self + (b - 1)`.
377    ///
378    /// # Panics
379    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
380    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
381    /// but it is always defined and safe (never causes undefined behavior)
382    #[allow(clippy::cast_possible_wrap)]
383    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
384        #[cfg(debug_assertions)]
385        {
386            let max_len = Self::safe_len(&(self..=Self::MAX));
387            assert!(
388                UIntPlusOne::zero() < b && b <= max_len,
389                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
390            );
391        }
392
393        let UIntPlusOne::UInt(b) = b else {
394            if self == Self::MIN {
395                return Self::MAX;
396            }
397            let max_len = Self::safe_len(&(self..=Self::MAX));
398            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
399        };
400        // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
401        self.wrapping_add((b - 1) as Self)
402    }
403
404    /// Computes the inclusive start of a range ending at `self` with length `b`,
405    /// by returning `self - (b - 1)`.
406    ///
407    /// # Panics
408    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
409    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
410    /// but it is always defined and safe (never causes undefined behavior).
411    #[allow(clippy::cast_possible_wrap)]
412    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
413        #[cfg(debug_assertions)]
414        {
415            let max_len = Self::safe_len(&(Self::MIN..=self));
416            assert!(
417                UIntPlusOne::zero() < b && b <= max_len,
418                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
419            );
420        }
421
422        let UIntPlusOne::UInt(b) = b else {
423            if self == Self::MAX {
424                return Self::MIN;
425            }
426            let max_len = Self::safe_len(&(Self::MIN..=self));
427            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
428        };
429
430        // If b is in range, two’s-complement wrap-around yields the correct inclusive start even if the subtraction overflows
431        self.wrapping_sub((b - 1) as Self)
432    }
433}
434
435impl Integer for u128 {
436    type SafeLen = UIntPlusOne<Self>;
437
438    #[inline]
439    fn checked_add_one(self) -> Option<Self> {
440        self.checked_add(1)
441    }
442
443    #[inline]
444    fn add_one(self) -> Self {
445        self + 1
446    }
447
448    #[inline]
449    fn sub_one(self) -> Self {
450        self - 1
451    }
452
453    #[inline]
454    fn assign_sub_one(&mut self) {
455        *self -= 1;
456    }
457
458    #[inline]
459    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
460        range.next()
461    }
462
463    #[inline]
464    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
465        range.next_back()
466    }
467
468    #[inline]
469    fn min_value() -> Self {
470        Self::MIN
471    }
472
473    #[inline]
474    fn max_value() -> Self {
475        Self::MAX
476    }
477
478    #[cfg(feature = "from_slice")]
479    #[inline]
480    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
481        RangeSetBlaze::from_iter(slice.as_ref())
482    }
483
484    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
485        debug_assert!(r.start() <= r.end());
486        UIntPlusOne::UInt(r.end() - r.start()) + UIntPlusOne::UInt(1)
487    }
488
489    #[allow(clippy::cast_precision_loss)]
490    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
491        match len {
492            UIntPlusOne::UInt(len) => len as f64,
493            UIntPlusOne::MaxPlusOne => UIntPlusOne::<Self>::max_plus_one_as_f64(),
494        }
495    }
496
497    #[allow(clippy::cast_sign_loss)]
498    #[allow(clippy::cast_possible_truncation)]
499    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
500        if f >= UIntPlusOne::<Self>::max_plus_one_as_f64() {
501            UIntPlusOne::MaxPlusOne
502        } else {
503            UIntPlusOne::UInt(f as Self)
504        }
505    }
506
507    /// Computes the inclusive end of a range starting at `self` with length `b`,
508    /// by returning `self + (b - 1)`.
509    ///
510    /// # Panics
511    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
512    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
513    /// but it is always defined and safe (never causes undefined behavior)
514    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
515        #[cfg(debug_assertions)]
516        {
517            let max_len = Self::safe_len(&(self..=Self::MAX));
518            assert!(
519                UIntPlusOne::zero() < b && b <= max_len,
520                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
521            );
522        }
523
524        let UIntPlusOne::UInt(b) = b else {
525            if self == Self::MIN {
526                return Self::MAX;
527            }
528            let max_len = Self::safe_len(&(self..=Self::MAX));
529            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
530        };
531        // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
532        self.wrapping_add((b - 1) as Self)
533    }
534
535    /// Computes the inclusive start of a range ending at `self` with length `b`,
536    /// by returning `self - (b - 1)`.
537    ///
538    /// # Panics
539    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
540    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
541    /// but it is always defined and safe (never causes undefined behavior).
542    #[allow(clippy::cast_possible_wrap)]
543    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
544        #[cfg(debug_assertions)]
545        {
546            let max_len = Self::safe_len(&(Self::MIN..=self));
547            assert!(
548                UIntPlusOne::zero() < b && b <= max_len,
549                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
550            );
551        }
552
553        let UIntPlusOne::UInt(b) = b else {
554            if self == Self::MAX {
555                return Self::MIN;
556            }
557            let max_len = Self::safe_len(&(Self::MIN..=self));
558            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
559        };
560
561        // If b is in range, two’s-complement wrap-around yields the correct inclusive start even if the subtraction overflows
562        self.wrapping_sub((b - 1) as Self)
563    }
564}
565
566impl Integer for isize {
567    #[cfg(target_pointer_width = "32")]
568    type SafeLen = u64;
569    #[cfg(target_pointer_width = "64")]
570    type SafeLen = u128;
571
572    impl_integer_ops!(isize, usize);
573}
574
575impl Integer for usize {
576    #[cfg(target_pointer_width = "32")]
577    type SafeLen = u64;
578    #[cfg(target_pointer_width = "64")]
579    type SafeLen = u128;
580
581    impl_integer_ops!(usize, Self);
582}
583
584impl Integer for i16 {
585    type SafeLen = u32;
586
587    impl_integer_ops!(i16, u16);
588}
589
590impl Integer for u16 {
591    type SafeLen = u32;
592
593    impl_integer_ops!(u16, Self);
594}
595
596impl Integer for Ipv4Addr {
597    type SafeLen = u64;
598
599    #[inline]
600    fn checked_add_one(self) -> Option<Self> {
601        let num = u32::from(self);
602        num.checked_add(1).map(Self::from)
603    }
604
605    #[inline]
606    fn add_one(self) -> Self {
607        let num = u32::from(self);
608        Self::from(num + 1)
609    }
610
611    #[inline]
612    fn sub_one(self) -> Self {
613        let num = u32::from(self);
614        Self::from(num - 1)
615    }
616
617    #[inline]
618    fn assign_sub_one(&mut self) {
619        let num = u32::from(*self);
620        *self = Self::from(num - 1);
621    }
622
623    #[inline]
624    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
625        range.next()
626    }
627
628    #[inline]
629    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
630        range.next_back()
631    }
632
633    #[inline]
634    fn min_value() -> Self {
635        Self::new(0, 0, 0, 0)
636    }
637
638    #[inline]
639    fn max_value() -> Self {
640        Self::new(255, 255, 255, 255)
641    }
642
643    #[cfg(feature = "from_slice")]
644    #[inline]
645    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
646        RangeSetBlaze::from_iter(slice.as_ref())
647    }
648
649    #[allow(clippy::cast_lossless)]
650    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
651        let start_num = u32::from(*r.start());
652        let end_num = u32::from(*r.end());
653        debug_assert!(start_num <= end_num);
654        // Signed sub may overflow, but casting preserves correct unsigned distance
655        end_num.overflowing_sub(start_num).0 as <Self as Integer>::SafeLen + 1
656    }
657
658    #[allow(clippy::cast_precision_loss)]
659    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
660        len as f64
661    }
662
663    #[allow(clippy::cast_possible_truncation)]
664    #[allow(clippy::cast_sign_loss)]
665    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
666        f as Self::SafeLen
667    }
668
669    #[allow(clippy::cast_possible_truncation)]
670    #[allow(clippy::cast_possible_wrap)]
671    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
672        #[cfg(debug_assertions)]
673        {
674            let max_len = Self::safe_len(&(self..=Self::max_value()));
675            assert!(
676                b > 0 && b <= max_len,
677                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
678            );
679        }
680        // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
681        u32::from(self).wrapping_add((b - 1) as u32).into()
682    }
683
684    #[allow(clippy::cast_possible_truncation)]
685    #[allow(clippy::cast_possible_wrap)]
686    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
687        #[cfg(debug_assertions)]
688        {
689            let max_len = Self::safe_len(&(Self::min_value()..=self));
690            assert!(
691                0 < b && b <= max_len,
692                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
693            );
694        }
695        // If b is in range, two’s-complement wrap-around yields the correct start even if the sub overflows
696        u32::from(self).wrapping_sub((b - 1) as u32).into()
697    }
698}
699
700impl Integer for Ipv6Addr {
701    type SafeLen = UIntPlusOne<u128>;
702
703    #[inline]
704    fn checked_add_one(self) -> Option<Self> {
705        let num = u128::from(self);
706        num.checked_add(1).map(Self::from)
707    }
708
709    #[inline]
710    fn add_one(self) -> Self {
711        let num = u128::from(self);
712        Self::from(num + 1)
713    }
714
715    #[inline]
716    fn sub_one(self) -> Self {
717        let num = u128::from(self);
718        Self::from(num - 1)
719    }
720
721    #[inline]
722    fn assign_sub_one(&mut self) {
723        let num = u128::from(*self);
724        *self = Self::from(num - 1);
725    }
726
727    #[inline]
728    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
729        range.next()
730    }
731
732    #[inline]
733    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
734        range.next_back()
735    }
736
737    #[inline]
738    fn min_value() -> Self {
739        Self::new(0, 0, 0, 0, 0, 0, 0, 0)
740    }
741
742    #[inline]
743    fn max_value() -> Self {
744        Self::from(u128::MAX)
745    }
746
747    #[cfg(feature = "from_slice")]
748    #[inline]
749    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
750        RangeSetBlaze::from_iter(slice.as_ref())
751    }
752
753    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
754        let start_num = u128::from(*r.start());
755        let end_num = u128::from(*r.end());
756
757        debug_assert!(start_num <= end_num);
758        UIntPlusOne::UInt(end_num - start_num) + UIntPlusOne::UInt(1)
759    }
760
761    #[allow(clippy::cast_precision_loss)]
762    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
763        match len {
764            UIntPlusOne::UInt(len) => len as f64,
765            UIntPlusOne::MaxPlusOne => UIntPlusOne::<u128>::max_plus_one_as_f64(),
766        }
767    }
768
769    #[allow(clippy::cast_possible_truncation)]
770    #[allow(clippy::cast_sign_loss)]
771    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
772        if f >= UIntPlusOne::<u128>::max_plus_one_as_f64() {
773            UIntPlusOne::MaxPlusOne
774        } else {
775            UIntPlusOne::UInt(f as u128)
776        }
777    }
778
779    /// Computes the inclusive end of a range starting at `self` with length `b`,
780    /// by returning `self + (b - 1)`.
781    ///
782    /// # Panics
783    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
784    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
785    /// but it is always defined and safe (never causes undefined behavior)
786    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
787        #[cfg(debug_assertions)]
788        {
789            let max_len = Self::safe_len(&(self..=Self::max_value()));
790            assert!(
791                UIntPlusOne::zero() < b && b <= max_len,
792                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
793            );
794        }
795
796        let UIntPlusOne::UInt(b) = b else {
797            if self == Self::min_value() {
798                return Self::max_value();
799            }
800            let max_len = Self::safe_len(&(self..=Self::max_value()));
801            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
802        };
803        // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
804        u128::from(self).wrapping_add(b - 1).into()
805    }
806
807    /// Computes the inclusive start of a range ending at `self` with length `b`,
808    /// by returning `self - (b - 1)`.
809    ///
810    /// # Panics
811    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
812    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
813    /// but it is always defined and safe (never causes undefined behavior).
814    #[allow(clippy::cast_possible_wrap)]
815    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
816        #[cfg(debug_assertions)]
817        {
818            let max_len = Self::safe_len(&(Self::min_value()..=self));
819            assert!(
820                UIntPlusOne::zero() < b && b <= max_len,
821                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
822            );
823        }
824
825        let UIntPlusOne::UInt(b) = b else {
826            if self == Self::max_value() {
827                return Self::min_value();
828            }
829            let max_len = Self::safe_len(&(Self::min_value()..=self));
830            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
831        };
832
833        // If b is in range, two’s-complement wrap-around yields the correct inclusive start even if the subtraction overflows
834        u128::from(self).wrapping_sub(b - 1).into()
835    }
836}
837
838// all inclusive
839const SURROGATE_START: u32 = 0xD800;
840const SURROGATE_END: u32 = 0xDFFF;
841
842impl Integer for char {
843    // in general, the length of a 32-bit inclusive range does not fit in a u32,
844    // but unicode doesn't use the full range, so it does fit
845    type SafeLen = u32;
846
847    #[inline]
848    fn checked_add_one(self) -> Option<Self> {
849        // Can't overflow u64 because of the range of char
850        let mut num = u32::from(self) + 1;
851        // skip over the surrogate range
852        if num == SURROGATE_START {
853            num = SURROGATE_END + 1;
854        }
855        // Will report char overflow as None
856        Self::from_u32(num)
857    }
858
859    #[inline]
860    fn add_one(self) -> Self {
861        self.checked_add_one().map_or_else(
862            || {
863                panic!("char overflow"); // Panics in both debug and release modes
864            },
865            |next| next,
866        )
867    }
868
869    #[inline]
870    fn sub_one(self) -> Self {
871        let mut num = u32::from(self).wrapping_sub(1);
872        if num == SURROGATE_END {
873            num = SURROGATE_START - 1;
874        }
875        Self::from_u32(num).expect("sub_one: underflow or invalid char (e.g., called on '\\u{0}')")
876    }
877
878    #[inline]
879    fn assign_sub_one(&mut self) {
880        *self = self.sub_one();
881    }
882
883    #[inline]
884    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
885        range.next()
886    }
887
888    #[inline]
889    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
890        range.next_back()
891    }
892
893    #[inline]
894    fn min_value() -> Self {
895        '\u{0}'
896    }
897
898    #[inline]
899    fn max_value() -> Self {
900        '\u{10FFFF}'
901    }
902
903    #[cfg(feature = "from_slice")]
904    #[inline]
905    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
906        RangeSetBlaze::from_iter(slice.as_ref())
907    }
908
909    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
910        // assume valid, non-empty range
911        let start_num = u32::from(*r.start());
912        let end_num = u32::from(*r.end());
913        let mut len = (end_num - start_num) as <Self as Integer>::SafeLen + 1;
914        if start_num < SURROGATE_START && SURROGATE_END < end_num {
915            len -= (SURROGATE_END - SURROGATE_START + 1) as <Self as Integer>::SafeLen;
916        }
917        len
918    }
919
920    #[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
921    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
922        len as f64
923    }
924
925    #[allow(clippy::cast_possible_truncation)]
926    #[allow(clippy::cast_sign_loss)]
927    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
928        f as Self::SafeLen
929    }
930
931    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
932        fn private_panic(a: char, b: u32) -> ! {
933            let max_len = char::safe_len(&(char::MIN..=a));
934            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
935        }
936
937        let Some(b_minus_one) = b.checked_sub(1) else {
938            private_panic(self, b);
939        };
940
941        let a = u32::from(self);
942        let Some(mut num) = a.checked_add(b_minus_one) else {
943            private_panic(self, b);
944        };
945        if a < SURROGATE_START && SURROGATE_START <= num {
946            let Some(num2) = num.checked_add(SURROGATE_END - SURROGATE_START + 1) else {
947                private_panic(self, b);
948            };
949            num = num2;
950        }
951
952        let Some(result) = Self::from_u32(num) else {
953            private_panic(self, b);
954        };
955        result
956    }
957
958    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
959        fn private_panic(a: char, b: u32) -> ! {
960            let max_len = char::safe_len(&(char::MIN..=a));
961            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
962        }
963
964        let Some(b_minus_one) = b.checked_sub(1) else {
965            private_panic(self, b);
966        };
967
968        let a = u32::from(self);
969        let Some(mut num) = a.checked_sub(b_minus_one) else {
970            private_panic(self, b);
971        };
972        if num <= SURROGATE_END && SURROGATE_END < a {
973            let Some(num2) = num.checked_sub(SURROGATE_END - SURROGATE_START + 1) else {
974                private_panic(self, b);
975            };
976            num = num2;
977        }
978
979        Self::from_u32(num).expect("Real Assert: Impossible for this to fail")
980    }
981}
982
983#[cfg(test)]
984mod tests {
985    use super::*;
986    use crate::prelude::*;
987    use num_traits::{One, Zero};
988    use syntactic_for::syntactic_for;
989
990    use wasm_bindgen_test::*;
991    wasm_bindgen_test_configure!(run_in_browser);
992
993    #[test]
994    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
995    fn coverage_integer() {
996        let mut a = 0u8..=0u8;
997        assert_eq!(u8::range_next_back(&mut a), Some(0));
998        assert_eq!(u8::range_next(&mut a), None);
999
1000        let mut b = 0i128..=0i128;
1001        assert_eq!(i128::range_next_back(&mut b), Some(0));
1002        assert_eq!(i128::range_next(&mut b), None);
1003
1004        let mut b = 0i128;
1005        i128::assign_sub_one(&mut b);
1006        assert_eq!(b, -1);
1007
1008        // convert  UIntPlusOne::MaxPlusOne to f64 and back
1009        let f = i128::safe_len_to_f64_lossy(UIntPlusOne::MaxPlusOne);
1010        let i = i128::f64_to_safe_len_lossy(f);
1011        assert_eq!(i, UIntPlusOne::MaxPlusOne);
1012
1013        let mut b = 0u128..=0u128;
1014        assert_eq!(u128::range_next_back(&mut b), Some(0));
1015        assert_eq!(u128::range_next(&mut b), None);
1016
1017        let mut b = 1u128;
1018        u128::assign_sub_one(&mut b);
1019        assert_eq!(b, 0);
1020
1021        // convert  UIntPlusOne::MaxPlusOne to f64 and back
1022        let f = u128::safe_len_to_f64_lossy(UIntPlusOne::MaxPlusOne);
1023        let i = u128::f64_to_safe_len_lossy(f);
1024        assert_eq!(i, UIntPlusOne::MaxPlusOne);
1025    }
1026
1027    #[test]
1028    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1029    #[should_panic(expected = "1")]
1030    #[cfg(debug_assertions)] // Only run this test in debug mode
1031    fn test_add_len_less_one_with_max_plus_one() {
1032        let value: i128 = 100;
1033        let len = UIntPlusOne::MaxPlusOne;
1034        let _ = value.inclusive_end_from_start(len); // This should panic in debug mode
1035    }
1036
1037    #[test]
1038    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1039    #[should_panic(expected = "2")]
1040    #[cfg(debug_assertions)] // Only run this test in debug mode
1041    fn test_sub_len_less_one_with_max_plus_one() {
1042        let value: i128 = 100;
1043        let len = UIntPlusOne::MaxPlusOne;
1044        let _ = value.start_from_inclusive_end(len); // This should panic in debug mode
1045    }
1046
1047    #[test]
1048    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1049    #[allow(clippy::cognitive_complexity, clippy::legacy_numeric_constants)]
1050    fn test_ipv4_and_ipv6_etc() {
1051        syntactic_for! { ty in [char, Ipv6Addr, u128, i128, Ipv4Addr] {
1052            $(
1053            // Test the minimum value for the type
1054            let a = <$ty>::min_value();
1055            let b = a.checked_add_one();
1056            assert_eq!(b, Some(<$ty>::min_value().add_one()));
1057
1058            // Show overflow behavior
1059            let a = <$ty>::max_value();
1060            let b = a.checked_add_one();
1061            assert_eq!(b, None);
1062
1063            let a = <$ty>::min_value();
1064            let mut b = a.add_one();
1065            assert_eq!(b, <$ty>::min_value().add_one());
1066
1067            let c = b.sub_one();
1068            assert_eq!(c, a);
1069
1070            b.assign_sub_one();
1071            assert_eq!(b, a);
1072
1073            let mut a = <$ty>::min_value()..=<$ty>::min_value();
1074            let b = <$ty>::range_next(&mut a);
1075            assert_eq!(b, Some(<$ty>::min_value()));
1076            let b = <$ty>::range_next(&mut a);
1077            assert_eq!(b, None);
1078
1079            let mut a = <$ty>::min_value()..=<$ty>::max_value();
1080            let b = <$ty>::range_next_back(&mut a);
1081            assert_eq!(b, Some(<$ty>::max_value()));
1082
1083            assert_eq!(<$ty>::min_value(), <$ty>::min_value());
1084
1085            let universe = <$ty>::min_value()..=<$ty>::max_value();
1086            let len = <$ty>::safe_len(&universe);
1087            assert_eq!(len, <$ty>::safe_len(&(<$ty>::min_value()..=<$ty>::max_value())));
1088
1089            let len_via_f64 = <$ty>::f64_to_safe_len_lossy(<$ty>::safe_len_to_f64_lossy(len));
1090            assert_eq!(len, len_via_f64);
1091
1092            let short = <$ty>::min_value()..=<$ty>::min_value();
1093            let len = <$ty>::safe_len(&short);
1094            let len_via_f64 = <$ty>::f64_to_safe_len_lossy(<$ty>::safe_len_to_f64_lossy(len));
1095            assert_eq!(len, len_via_f64);
1096
1097            let len = <$ty>::safe_len(&universe);
1098            let b = <$ty>::min_value().inclusive_end_from_start(len);
1099            assert_eq!(b, <$ty>::max_value());
1100
1101            let c = b.start_from_inclusive_end(len);
1102            assert_eq!(c, <$ty>::min_value());
1103
1104            let range = <$ty>::min_value()..=<$ty>::min_value().add_one();
1105            let len2 = <$ty>::safe_len(&range);
1106            let b = <$ty>::min_value().inclusive_end_from_start(len2);
1107            assert_eq!(b, <$ty>::min_value().add_one());
1108
1109            let b = <$ty>::max_value().start_from_inclusive_end(len2);
1110            assert_eq!(b, <$ty>::max_value().sub_one());
1111
1112            #[cfg(feature = "from_slice")]
1113            {
1114                let range_set_blaze = <$ty>::from_slice(&[<$ty>::min_value()]);
1115                assert_eq!(range_set_blaze, RangeSetBlaze::from_iter([<$ty>::min_value()]));
1116            }
1117            )*
1118        }}
1119    }
1120
1121    #[test]
1122    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1123    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1124    #[allow(clippy::legacy_numeric_constants)]
1125    fn test_i128_overflow() {
1126        let value: i128 = i128::max_value();
1127        let _ = value.inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1128    }
1129
1130    #[test]
1131    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1132    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1133    #[allow(clippy::legacy_numeric_constants)]
1134    fn test_i128_underflow() {
1135        let value: i128 = i128::min_value();
1136        let _ = value.start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1137    }
1138
1139    #[test]
1140    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1141    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1142    #[allow(clippy::legacy_numeric_constants)]
1143    fn test_u128_overflow() {
1144        let value: u128 = u128::max_value();
1145        let _ = value.inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1146    }
1147
1148    #[test]
1149    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1150    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1151    #[allow(clippy::legacy_numeric_constants)]
1152    fn test_u128_underflow() {
1153        let value: u128 = u128::min_value();
1154        let _ = value.start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1155    }
1156
1157    #[test]
1158    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1159    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1160    #[allow(clippy::legacy_numeric_constants)]
1161    fn test_ipv6_overflow() {
1162        let value: Ipv6Addr = Ipv6Addr::max_value();
1163        let _ = value.inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1164    }
1165
1166    #[test]
1167    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1168    #[should_panic(expected = "char overflow")]
1169    #[allow(clippy::legacy_numeric_constants)]
1170    fn test_char0_overflow() {
1171        let value: char = char::max_value();
1172        let _ = value.add_one();
1173    }
1174
1175    #[test]
1176    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1177    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1112064)")]
1178    #[allow(clippy::legacy_numeric_constants)]
1179    fn test_char1_overflow() {
1180        let value: char = char::max_value();
1181        let len2 = char::safe_len(&(char::min_value()..=char::min_value().add_one()));
1182        let _ = value.inclusive_end_from_start(len2);
1183    }
1184
1185    #[test]
1186    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1187    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1188    #[allow(clippy::legacy_numeric_constants)]
1189    fn test_char1_underflow() {
1190        let value: char = char::min_value();
1191        let len2 = char::safe_len(&(char::min_value()..=char::min_value().add_one()));
1192        let _ = value.start_from_inclusive_end(len2);
1193    }
1194
1195    #[test]
1196    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1197    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1198    fn test_ipv6_underflow() {
1199        let value: Ipv6Addr = Ipv6Addr::min_value();
1200        let _ = value.start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1201    }
1202
1203    #[test]
1204    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1205    #[allow(clippy::cognitive_complexity)]
1206    fn test_char() {
1207        // This loops over 1 million characters, but it seems fast enough.
1208        // Define the universe as the complement of an empty RangeSetBlaze
1209        let universe = !RangeSetBlaze::<char>::default();
1210
1211        // Check add_one and sub_one behavior
1212        let max_value = <char as Integer>::max_value();
1213        assert_eq!(max_value.checked_add_one(), None);
1214
1215        let mut prev = None;
1216        let mut len = <char as Integer>::SafeLen::zero();
1217        for item in <char as Integer>::min_value()..=max_value {
1218            let len2b = <char as Integer>::safe_len(&(item..=max_value));
1219            let mut expected = universe.len();
1220            expected -= len;
1221            assert_eq!(len2b, expected);
1222
1223            let item2 = max_value.start_from_inclusive_end(len2b);
1224            assert_eq!(item2, item);
1225
1226            let item3 = item2.inclusive_end_from_start(len2b);
1227            assert_eq!(item3, max_value);
1228
1229            len += <char as Integer>::SafeLen::one();
1230            let len2 = <char as Integer>::safe_len(&(<char as Integer>::min_value()..=item));
1231            assert_eq!(len, len2);
1232            assert_eq!(
1233                len2,
1234                <char as Integer>::f64_to_safe_len_lossy(<char as Integer>::safe_len_to_f64_lossy(
1235                    len2
1236                ))
1237            );
1238
1239            let item2 = <char as Integer>::min_value().inclusive_end_from_start(len);
1240            assert_eq!(item2, item);
1241
1242            let item3 = item.start_from_inclusive_end(len);
1243            assert_eq!(item3, <char as Integer>::min_value());
1244
1245            if let Some(prev) = prev {
1246                assert!(universe.contains(prev));
1247                assert!(universe.contains(item));
1248                assert!(universe.is_superset(&RangeSetBlaze::from_iter([prev..=item])));
1249
1250                assert_eq!(prev.checked_add_one(), Some(item));
1251                assert_eq!(prev.add_one(), item);
1252
1253                assert_eq!(item.sub_one(), prev);
1254                let mut item2 = item;
1255                item2.assign_sub_one();
1256                assert_eq!(item2, prev);
1257            }
1258
1259            prev = Some(item);
1260        }
1261        assert_eq!(universe.len(), len);
1262
1263        // Additional checks can be added here if needed for coverage
1264    }
1265
1266    #[test]
1267    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1268    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 66)")]
1269    fn test_add_len_less_one_panic_conditions1() {
1270        // Case 1: `b.checked_sub(1)` returns `None`
1271        let character = 'A';
1272        let b = 0;
1273        _ = character.inclusive_end_from_start(b); // This should panic due to overflow
1274    }
1275
1276    #[test]
1277    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1278    #[should_panic(expected = "b must be in range 1..=max_len (b = 3, max_len = 1112064)")]
1279    fn test_add_len_less_one_panic_conditions2() {
1280        // Case 2: `self.checked_add(b_less_one)` returns `None`
1281        let character = char::MAX;
1282        let b = 3;
1283        _ = character.inclusive_end_from_start(b); // This should panic due to overflow
1284    }
1285
1286    #[test]
1287    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1288    #[should_panic(expected = "b must be in range 1..=max_len (b = 4294967295, max_len = 66)")]
1289    fn test_add_len_less_one_panic_conditions3() {
1290        // Case 3: overflow when adding `b - 1` to `self`
1291        let character = 'A';
1292        let b = u32::MAX;
1293        _ = character.inclusive_end_from_start(b); // This should panic due to overflow
1294    }
1295
1296    #[test]
1297    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1298    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 66)")]
1299    fn test_sub_len_less_one_panic_conditions1() {
1300        // Case 1: `b.checked_sub(1)` fails, causing an immediate panic.
1301        let character = 'A';
1302        let b = 0;
1303        _ = character.start_from_inclusive_end(b); // This should panic due to underflow
1304    }
1305
1306    #[test]
1307    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1308    #[should_panic(expected = "b must be in range 1..=max_len (b = 4294967295, max_len = 66)")]
1309    fn test_sub_len_less_one_panic_conditions2() {
1310        // Case 2: `a.checked_sub(b_less_one)` fails, causing underflow.
1311        let character = 'A';
1312        let b = u32::MAX;
1313        _ = character.start_from_inclusive_end(b); // This should panic due to underflow
1314    }
1315
1316    #[allow(clippy::legacy_numeric_constants, clippy::cognitive_complexity)]
1317    #[test]
1318    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1319    fn test_use_of_as_00() {
1320        syntactic_for! { ty in [char, i8, i16, i32, i64, i128, isize, Ipv4Addr, Ipv6Addr, u8, u16, u32, u64, u128, usize] {
1321            $(
1322        let a = <$ty>::min_value();
1323        let b = <$ty>::max_value();
1324        let len = <$ty>::safe_len(&(a..=b));
1325        assert_eq!(<$ty>::inclusive_end_from_start(a, len), b);
1326        assert_eq!(<$ty>::start_from_inclusive_end(b, len), a);
1327            )*
1328        }}
1329    }
1330
1331    #[cfg(debug_assertions)]
1332    #[test]
1333    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1334    fn test_use_of_as_01() {
1335        let _ = 127i8.inclusive_end_from_start(0);
1336    }
1337
1338    #[cfg(not(debug_assertions))]
1339    #[test]
1340    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1341    fn test_use_of_as_02() {
1342        assert_eq!(127i8.inclusive_end_from_start(0), 126);
1343        assert_eq!(127i8.start_from_inclusive_end(0), -128);
1344        assert_eq!(127i8.inclusive_end_from_start(2), -128);
1345        assert_eq!((-126i8).start_from_inclusive_end(4), 127);
1346    }
1347
1348    #[cfg(debug_assertions)]
1349    #[test]
1350    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 256)")]
1351    fn test_use_of_as_03() {
1352        let _ = 127i8.start_from_inclusive_end(0);
1353    }
1354
1355    #[cfg(debug_assertions)]
1356    #[test]
1357    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1358    fn test_use_of_as_04() {
1359        let _ = 127i8.inclusive_end_from_start(2);
1360    }
1361
1362    #[cfg(debug_assertions)]
1363    #[test]
1364    #[should_panic(expected = "b must be in range 1..=max_len (b = 4, max_len = 3)")]
1365    fn test_use_of_as_05() {
1366        let _ = (-126i8).start_from_inclusive_end(4);
1367    }
1368
1369    #[test]
1370    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1371    fn test_use_of_as_06() {
1372        for a in (-128i8)..=127i8 {
1373            let b = i8::safe_len(&(a..=127i8));
1374            assert_eq!(a.inclusive_end_from_start(b), 127i8);
1375            let b = i8::safe_len(&(i8::MIN..=a));
1376            assert_eq!(a.start_from_inclusive_end(b), -128i8);
1377        }
1378    }
1379
1380    // make full tests for i128
1381    #[cfg(debug_assertions)]
1382    #[test]
1383    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1384    fn test_use_of_as_11() {
1385        let _ = i128::MAX.inclusive_end_from_start(UIntPlusOne::zero());
1386    }
1387
1388    #[cfg(not(debug_assertions))]
1389    #[test]
1390    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1391    fn test_use_of_as_12() {
1392        assert_eq!(
1393            i128::MAX.inclusive_end_from_start(UIntPlusOne::zero()),
1394            170141183460469231731687303715884105726
1395        );
1396        assert_eq!(
1397            i128::MAX.start_from_inclusive_end(UIntPlusOne::zero()),
1398            -170141183460469231731687303715884105728
1399        );
1400        assert_eq!(
1401            i128::MAX.inclusive_end_from_start(UIntPlusOne::UInt(2)),
1402            -170141183460469231731687303715884105728
1403        );
1404        assert_eq!(
1405            (i128::MIN).start_from_inclusive_end(UIntPlusOne::UInt(2)),
1406            170141183460469231731687303715884105727
1407        );
1408    }
1409
1410    #[cfg(debug_assertions)]
1411    #[test]
1412    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = (u128::MAX + 1)")]
1413    fn test_use_of_as_13() {
1414        let _ = i128::MAX.start_from_inclusive_end(UIntPlusOne::zero());
1415    }
1416
1417    #[cfg(debug_assertions)]
1418    #[test]
1419    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1420    fn test_use_of_as_14() {
1421        let _ = i128::MAX.inclusive_end_from_start(UIntPlusOne::UInt(2));
1422    }
1423
1424    #[cfg(debug_assertions)]
1425    #[test]
1426    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1427    fn test_use_of_as_15() {
1428        let _ = (i128::MIN).start_from_inclusive_end(UIntPlusOne::UInt(2));
1429    }
1430
1431    #[test]
1432    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1433    fn test_use_of_as_16() {
1434        assert_eq!(
1435            (i128::MIN).inclusive_end_from_start(UIntPlusOne::MaxPlusOne),
1436            i128::MAX
1437        );
1438        assert_eq!(
1439            (i128::MAX).start_from_inclusive_end(UIntPlusOne::MaxPlusOne),
1440            i128::MIN
1441        );
1442    }
1443
1444    #[test]
1445    #[should_panic(
1446        expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 170141183460469231731687303715884105728)"
1447    )]
1448    fn test_use_of_as_17() {
1449        let _ = (0i128).inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1450    }
1451
1452    #[test]
1453    #[should_panic(
1454        expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 170141183460469231731687303715884105729)"
1455    )]
1456    fn test_use_of_as_18() {
1457        let _ = (0i128).start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1458    }
1459
1460    // make full tests for u128
1461    #[cfg(debug_assertions)]
1462    #[test]
1463    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1464    fn test_use_of_as_21() {
1465        let _ = u128::MAX.inclusive_end_from_start(UIntPlusOne::zero());
1466    }
1467
1468    #[cfg(not(debug_assertions))]
1469    #[test]
1470    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1471    fn test_use_of_as_22() {
1472        assert_eq!(
1473            u128::MAX.inclusive_end_from_start(UIntPlusOne::zero()),
1474            340282366920938463463374607431768211454
1475        );
1476        assert_eq!(u128::MAX.start_from_inclusive_end(UIntPlusOne::zero()), 0);
1477        assert_eq!(u128::MAX.inclusive_end_from_start(UIntPlusOne::UInt(2)), 0);
1478        assert_eq!(
1479            (u128::MIN).start_from_inclusive_end(UIntPlusOne::UInt(2)),
1480            340282366920938463463374607431768211455
1481        );
1482    }
1483
1484    #[cfg(debug_assertions)]
1485    #[test]
1486    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = (u128::MAX + 1)")]
1487    fn test_use_of_as_23() {
1488        let _ = u128::MAX.start_from_inclusive_end(UIntPlusOne::zero());
1489    }
1490
1491    #[cfg(debug_assertions)]
1492    #[test]
1493    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1494    fn test_use_of_as_24() {
1495        let _ = u128::MAX.inclusive_end_from_start(UIntPlusOne::UInt(2));
1496    }
1497
1498    #[cfg(debug_assertions)]
1499    #[test]
1500    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1501    fn test_use_of_as_25() {
1502        let _ = (u128::MIN).start_from_inclusive_end(UIntPlusOne::UInt(2));
1503    }
1504
1505    #[test]
1506    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1507    fn test_use_of_as_26() {
1508        assert_eq!(
1509            (u128::MIN).inclusive_end_from_start(UIntPlusOne::MaxPlusOne),
1510            u128::MAX
1511        );
1512        assert_eq!(
1513            (u128::MAX).start_from_inclusive_end(UIntPlusOne::MaxPlusOne),
1514            u128::MIN
1515        );
1516    }
1517
1518    #[test]
1519    #[should_panic(
1520        expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 340282366920938463463374607431768211454)"
1521    )]
1522    fn test_use_of_as_27() {
1523        let _ = (2u128).inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1524    }
1525
1526    #[test]
1527    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1528    fn test_use_of_as_28() {
1529        let _ = (0u128).start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1530    }
1531
1532    // make full tests for Ipv4Addr
1533    #[cfg(debug_assertions)]
1534    #[test]
1535    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1536    fn test_use_of_as_31() {
1537        let _ = Ipv4Addr::max_value().inclusive_end_from_start(0);
1538    }
1539
1540    #[cfg(not(debug_assertions))]
1541    #[test]
1542    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1543    fn test_use_of_as_32() {
1544        assert_eq!(
1545            Ipv4Addr::max_value().inclusive_end_from_start(0),
1546            Ipv4Addr::new(255, 255, 255, 254)
1547        );
1548        assert_eq!(
1549            Ipv4Addr::max_value().start_from_inclusive_end(0),
1550            Ipv4Addr::from(0)
1551        );
1552        assert_eq!(
1553            Ipv4Addr::max_value().inclusive_end_from_start(2),
1554            Ipv4Addr::from(0)
1555        );
1556        assert_eq!(
1557            Ipv4Addr::min_value().start_from_inclusive_end(2),
1558            Ipv4Addr::new(255, 255, 255, 255)
1559        );
1560        assert_eq!(
1561            Ipv4Addr::new(0, 0, 0, 2).inclusive_end_from_start(u64::MAX),
1562            Ipv4Addr::from(0)
1563        );
1564
1565        assert_eq!(
1566            Ipv4Addr::new(0, 0, 0, 0).start_from_inclusive_end(u64::MAX),
1567            Ipv4Addr::new(0, 0, 0, 2)
1568        );
1569    }
1570
1571    #[cfg(debug_assertions)]
1572    #[test]
1573    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 4294967296)")]
1574    fn test_use_of_as_33() {
1575        let _ = Ipv4Addr::max_value().start_from_inclusive_end(0);
1576    }
1577
1578    #[cfg(debug_assertions)]
1579    #[test]
1580    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1581    fn test_use_of_as_34() {
1582        let _ = Ipv4Addr::max_value().inclusive_end_from_start(2);
1583    }
1584
1585    #[cfg(debug_assertions)]
1586    #[test]
1587    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1588    fn test_use_of_as_35() {
1589        let _ = (Ipv4Addr::min_value()).start_from_inclusive_end(2);
1590    }
1591
1592    // ipv6
1593
1594    #[cfg(debug_assertions)]
1595    #[test]
1596    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1597    fn test_use_of_as_41() {
1598        let _ = Ipv6Addr::max_value().inclusive_end_from_start(UIntPlusOne::zero());
1599    }
1600
1601    #[cfg(not(debug_assertions))]
1602    #[test]
1603    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1604    fn test_use_of_as_42() {
1605        assert_eq!(
1606            Ipv6Addr::max_value().inclusive_end_from_start(UIntPlusOne::zero()),
1607            Ipv6Addr::from(340282366920938463463374607431768211454)
1608        );
1609        assert_eq!(
1610            Ipv6Addr::max_value().start_from_inclusive_end(UIntPlusOne::zero()),
1611            Ipv6Addr::from(0)
1612        );
1613        assert_eq!(
1614            Ipv6Addr::max_value().inclusive_end_from_start(UIntPlusOne::UInt(2)),
1615            Ipv6Addr::from(0)
1616        );
1617        assert_eq!(
1618            (Ipv6Addr::min_value()).start_from_inclusive_end(UIntPlusOne::UInt(2)),
1619            Ipv6Addr::from(340282366920938463463374607431768211455)
1620        );
1621    }
1622
1623    #[cfg(debug_assertions)]
1624    #[test]
1625    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = (u128::MAX + 1)")]
1626    fn test_use_of_as_43() {
1627        let _ = Ipv6Addr::max_value().start_from_inclusive_end(UIntPlusOne::zero());
1628    }
1629
1630    #[cfg(debug_assertions)]
1631    #[test]
1632    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1633    fn test_use_of_as_44() {
1634        let _ = Ipv6Addr::max_value().inclusive_end_from_start(UIntPlusOne::UInt(2));
1635    }
1636
1637    #[cfg(debug_assertions)]
1638    #[test]
1639    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1640    fn test_use_of_as_45() {
1641        let _ = (Ipv6Addr::min_value()).start_from_inclusive_end(UIntPlusOne::UInt(2));
1642    }
1643
1644    #[test]
1645    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1646    fn test_use_of_as_46() {
1647        assert_eq!(
1648            (Ipv6Addr::min_value()).inclusive_end_from_start(UIntPlusOne::MaxPlusOne),
1649            Ipv6Addr::max_value()
1650        );
1651        assert_eq!(
1652            (Ipv6Addr::max_value()).start_from_inclusive_end(UIntPlusOne::MaxPlusOne),
1653            Ipv6Addr::min_value()
1654        );
1655    }
1656
1657    #[test]
1658    #[should_panic(
1659        expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 340282366920938463463374607431768211454)"
1660    )]
1661    fn test_use_of_as_47() {
1662        let _ = Ipv6Addr::from(2u128).inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1663    }
1664
1665    #[test]
1666    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1667    fn test_use_of_as_48() {
1668        let _ = Ipv6Addr::from(0u128).start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1669    }
1670
1671    // char
1672
1673    #[test]
1674    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1112064)")]
1675    fn test_use_of_as_51() {
1676        let _ = char::max_value().inclusive_end_from_start(0);
1677    }
1678
1679    #[test]
1680    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1112064)")]
1681    fn test_use_of_as_53() {
1682        let _ = char::max_value().start_from_inclusive_end(0);
1683    }
1684
1685    #[test]
1686    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1112064)")]
1687    fn test_use_of_as_54() {
1688        let _ = char::max_value().inclusive_end_from_start(2);
1689    }
1690
1691    #[test]
1692    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1693    fn test_use_of_as_55() {
1694        let _ = (char::min_value()).start_from_inclusive_end(2);
1695    }
1696
1697    #[test]
1698    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1699    fn test_use_of_as_56() {
1700        assert_eq!(
1701            (char::min_value()).inclusive_end_from_start(1_112_064),
1702            char::max_value()
1703        );
1704        assert_eq!(
1705            (char::max_value()).start_from_inclusive_end(1_112_064),
1706            char::min_value()
1707        );
1708    }
1709
1710    #[test]
1711    #[should_panic(expected = "b must be in range 1..=max_len (b = 1112064, max_len = 3)")]
1712    fn test_use_of_as_57() {
1713        let _ = '\x02'.inclusive_end_from_start(1_112_064);
1714    }
1715
1716    #[test]
1717    #[should_panic(expected = "b must be in range 1..=max_len (b = 1112064, max_len = 1)")]
1718    fn test_use_of_as_58() {
1719        let _ = '\x00'.start_from_inclusive_end(1_112_064);
1720    }
1721
1722    #[test]
1723    #[cfg(debug_assertions)]
1724    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1725    #[should_panic(expected = "assertion failed: r.start() <= r.end()")]
1726    #[allow(clippy::reversed_empty_ranges)]
1727    fn test_safe_len() {
1728        let i = 0u128..=0u128;
1729        assert_eq!(u128::safe_len(&i), UIntPlusOne::UInt(1));
1730
1731        let i = 0u128..=1u128;
1732        assert_eq!(u128::safe_len(&i), UIntPlusOne::UInt(2));
1733
1734        let i = 1u128..=0u128;
1735        // This call is expected to panic due to the debug_assert in safe_len
1736        let _ = u128::safe_len(&i);
1737    }
1738
1739    #[test]
1740    #[cfg(debug_assertions)]
1741    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1742    #[should_panic(expected = "assertion failed: r.start() <= r.end()")]
1743    #[allow(clippy::reversed_empty_ranges)]
1744    fn safe_len2() {
1745        let i = 0u128..=0u128;
1746        assert_eq!(u128::safe_len(&i), UIntPlusOne::UInt(1));
1747
1748        let i = 0u128..=1u128;
1749        assert_eq!(u128::safe_len(&i), UIntPlusOne::UInt(2));
1750
1751        let i = 1u128..=0u128;
1752        // This call is expected to panic due to the debug_assert in safe_len
1753        let _ = u128::safe_len(&i);
1754    }
1755
1756    #[test]
1757    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1758    #[should_panic(expected = "b must be in range 1..=max_len (b = 4294911999, max_len = 55295)")]
1759    fn safe_len_char1() {
1760        let a = '\u{D7FE}';
1761        let len = 4_294_911_999u32;
1762        let _ = a.inclusive_end_from_start(len);
1763    }
1764
1765    #[test]
1766    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1767    #[should_panic(expected = "b must be in range 1..=max_len (b = 57343, max_len = 55297)")]
1768    fn safe_len_char2() {
1769        let a = '\u{E000}';
1770        let len = 0xDFFFu32;
1771        let _ = a.start_from_inclusive_end(len);
1772    }
1773}