Skip to main content

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