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            // This is only reached in release builds.
398            let max_len = Self::safe_len(&(self..=Self::MAX));
399            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
400        };
401        // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
402        self.wrapping_add((b - 1) as Self)
403    }
404
405    /// Computes the inclusive start of a range ending at `self` with length `b`,
406    /// by returning `self - (b - 1)`.
407    ///
408    /// # Panics
409    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
410    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
411    /// but it is always defined and safe (never causes undefined behavior).
412    #[allow(clippy::cast_possible_wrap)]
413    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
414        #[cfg(debug_assertions)]
415        {
416            let max_len = Self::safe_len(&(Self::MIN..=self));
417            assert!(
418                UIntPlusOne::zero() < b && b <= max_len,
419                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
420            );
421        }
422
423        let UIntPlusOne::UInt(b) = b else {
424            if self == Self::MAX {
425                return Self::MIN;
426            }
427            // This is only reached in release builds.
428            let max_len = Self::safe_len(&(Self::MIN..=self));
429            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
430        };
431
432        // If b is in range, two’s-complement wrap-around yields the correct inclusive start even if the subtraction overflows
433        self.wrapping_sub((b - 1) as Self)
434    }
435}
436
437impl Integer for u128 {
438    type SafeLen = UIntPlusOne<Self>;
439
440    #[inline]
441    fn checked_add_one(self) -> Option<Self> {
442        self.checked_add(1)
443    }
444
445    #[inline]
446    fn add_one(self) -> Self {
447        self + 1
448    }
449
450    #[inline]
451    fn sub_one(self) -> Self {
452        self - 1
453    }
454
455    #[inline]
456    fn assign_sub_one(&mut self) {
457        *self -= 1;
458    }
459
460    #[inline]
461    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
462        range.next()
463    }
464
465    #[inline]
466    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
467        range.next_back()
468    }
469
470    #[inline]
471    fn min_value() -> Self {
472        Self::MIN
473    }
474
475    #[inline]
476    fn max_value() -> Self {
477        Self::MAX
478    }
479
480    #[cfg(feature = "from_slice")]
481    #[inline]
482    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
483        RangeSetBlaze::from_iter(slice.as_ref())
484    }
485
486    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
487        debug_assert!(r.start() <= r.end());
488        UIntPlusOne::UInt(r.end() - r.start()) + UIntPlusOne::UInt(1)
489    }
490
491    #[allow(clippy::cast_precision_loss)]
492    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
493        match len {
494            UIntPlusOne::UInt(len) => len as f64,
495            UIntPlusOne::MaxPlusOne => UIntPlusOne::<Self>::max_plus_one_as_f64(),
496        }
497    }
498
499    #[allow(clippy::cast_sign_loss)]
500    #[allow(clippy::cast_possible_truncation)]
501    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
502        if f >= UIntPlusOne::<Self>::max_plus_one_as_f64() {
503            UIntPlusOne::MaxPlusOne
504        } else {
505            UIntPlusOne::UInt(f as Self)
506        }
507    }
508
509    /// Computes the inclusive end of a range starting at `self` with length `b`,
510    /// by returning `self + (b - 1)`.
511    ///
512    /// # Panics
513    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
514    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
515    /// but it is always defined and safe (never causes undefined behavior)
516    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
517        #[cfg(debug_assertions)]
518        {
519            let max_len = Self::safe_len(&(self..=Self::MAX));
520            assert!(
521                UIntPlusOne::zero() < b && b <= max_len,
522                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
523            );
524        }
525
526        let UIntPlusOne::UInt(b) = b else {
527            if self == Self::MIN {
528                return Self::MAX;
529            }
530            // This is only reached in release builds.
531            let max_len = Self::safe_len(&(self..=Self::MAX));
532            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
533        };
534        // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
535        self.wrapping_add((b - 1) as Self)
536    }
537
538    /// Computes the inclusive start of a range ending at `self` with length `b`,
539    /// by returning `self - (b - 1)`.
540    ///
541    /// # Panics
542    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
543    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
544    /// but it is always defined and safe (never causes undefined behavior).
545    #[allow(clippy::cast_possible_wrap)]
546    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
547        #[cfg(debug_assertions)]
548        {
549            let max_len = Self::safe_len(&(Self::MIN..=self));
550            assert!(
551                UIntPlusOne::zero() < b && b <= max_len,
552                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
553            );
554        }
555
556        let UIntPlusOne::UInt(b) = b else {
557            if self == Self::MAX {
558                return Self::MIN;
559            }
560            // This is only reached in release builds.
561            let max_len = Self::safe_len(&(Self::MIN..=self));
562            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
563        };
564
565        // If b is in range, two’s-complement wrap-around yields the correct inclusive start even if the subtraction overflows
566        self.wrapping_sub((b - 1) as Self)
567    }
568}
569
570impl Integer for isize {
571    #[cfg(target_pointer_width = "32")]
572    type SafeLen = u64;
573    #[cfg(target_pointer_width = "64")]
574    type SafeLen = u128;
575
576    impl_integer_ops!(isize, usize);
577}
578
579impl Integer for usize {
580    #[cfg(target_pointer_width = "32")]
581    type SafeLen = u64;
582    #[cfg(target_pointer_width = "64")]
583    type SafeLen = u128;
584
585    impl_integer_ops!(usize, Self);
586}
587
588impl Integer for i16 {
589    type SafeLen = u32;
590
591    impl_integer_ops!(i16, u16);
592}
593
594impl Integer for u16 {
595    type SafeLen = u32;
596
597    impl_integer_ops!(u16, Self);
598}
599
600impl Integer for Ipv4Addr {
601    type SafeLen = u64;
602
603    #[inline]
604    fn checked_add_one(self) -> Option<Self> {
605        let num = u32::from(self);
606        num.checked_add(1).map(Self::from)
607    }
608
609    #[inline]
610    fn add_one(self) -> Self {
611        let num = u32::from(self);
612        Self::from(num + 1)
613    }
614
615    #[inline]
616    fn sub_one(self) -> Self {
617        let num = u32::from(self);
618        Self::from(num - 1)
619    }
620
621    #[inline]
622    fn assign_sub_one(&mut self) {
623        let num = u32::from(*self);
624        *self = Self::from(num - 1);
625    }
626
627    #[inline]
628    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
629        range.next()
630    }
631
632    #[inline]
633    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
634        range.next_back()
635    }
636
637    #[inline]
638    fn min_value() -> Self {
639        Self::new(0, 0, 0, 0)
640    }
641
642    #[inline]
643    fn max_value() -> Self {
644        Self::new(255, 255, 255, 255)
645    }
646
647    #[cfg(feature = "from_slice")]
648    #[inline]
649    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
650        RangeSetBlaze::from_iter(slice.as_ref())
651    }
652
653    #[allow(clippy::cast_lossless)]
654    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
655        let start_num = u32::from(*r.start());
656        let end_num = u32::from(*r.end());
657        debug_assert!(start_num <= end_num);
658        // Signed sub may overflow, but casting preserves correct unsigned distance
659        end_num.overflowing_sub(start_num).0 as <Self as Integer>::SafeLen + 1
660    }
661
662    #[allow(clippy::cast_precision_loss)]
663    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
664        len as f64
665    }
666
667    #[allow(clippy::cast_possible_truncation)]
668    #[allow(clippy::cast_sign_loss)]
669    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
670        f as Self::SafeLen
671    }
672
673    #[allow(clippy::cast_possible_truncation)]
674    #[allow(clippy::cast_possible_wrap)]
675    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
676        #[cfg(debug_assertions)]
677        {
678            let max_len = Self::safe_len(&(self..=Self::max_value()));
679            assert!(
680                b > 0 && b <= max_len,
681                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
682            );
683        }
684        // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
685        u32::from(self).wrapping_add((b - 1) as u32).into()
686    }
687
688    #[allow(clippy::cast_possible_truncation)]
689    #[allow(clippy::cast_possible_wrap)]
690    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
691        #[cfg(debug_assertions)]
692        {
693            let max_len = Self::safe_len(&(Self::min_value()..=self));
694            assert!(
695                0 < b && b <= max_len,
696                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
697            );
698        }
699        // If b is in range, two’s-complement wrap-around yields the correct start even if the sub overflows
700        u32::from(self).wrapping_sub((b - 1) as u32).into()
701    }
702}
703
704impl Integer for Ipv6Addr {
705    type SafeLen = UIntPlusOne<u128>;
706
707    #[inline]
708    fn checked_add_one(self) -> Option<Self> {
709        let num = u128::from(self);
710        num.checked_add(1).map(Self::from)
711    }
712
713    #[inline]
714    fn add_one(self) -> Self {
715        let num = u128::from(self);
716        Self::from(num + 1)
717    }
718
719    #[inline]
720    fn sub_one(self) -> Self {
721        let num = u128::from(self);
722        Self::from(num - 1)
723    }
724
725    #[inline]
726    fn assign_sub_one(&mut self) {
727        let num = u128::from(*self);
728        *self = Self::from(num - 1);
729    }
730
731    #[inline]
732    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
733        range.next()
734    }
735
736    #[inline]
737    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
738        range.next_back()
739    }
740
741    #[inline]
742    fn min_value() -> Self {
743        Self::new(0, 0, 0, 0, 0, 0, 0, 0)
744    }
745
746    #[inline]
747    fn max_value() -> Self {
748        Self::from(u128::MAX)
749    }
750
751    #[cfg(feature = "from_slice")]
752    #[inline]
753    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
754        RangeSetBlaze::from_iter(slice.as_ref())
755    }
756
757    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
758        let start_num = u128::from(*r.start());
759        let end_num = u128::from(*r.end());
760
761        debug_assert!(start_num <= end_num);
762        UIntPlusOne::UInt(end_num - start_num) + UIntPlusOne::UInt(1)
763    }
764
765    #[allow(clippy::cast_precision_loss)]
766    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
767        match len {
768            UIntPlusOne::UInt(len) => len as f64,
769            UIntPlusOne::MaxPlusOne => UIntPlusOne::<u128>::max_plus_one_as_f64(),
770        }
771    }
772
773    #[allow(clippy::cast_possible_truncation)]
774    #[allow(clippy::cast_sign_loss)]
775    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
776        if f >= UIntPlusOne::<u128>::max_plus_one_as_f64() {
777            UIntPlusOne::MaxPlusOne
778        } else {
779            UIntPlusOne::UInt(f as u128)
780        }
781    }
782
783    /// Computes the inclusive end of a range starting at `self` with length `b`,
784    /// by returning `self + (b - 1)`.
785    ///
786    /// # Panics
787    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
788    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
789    /// but it is always defined and safe (never causes undefined behavior)
790    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
791        #[cfg(debug_assertions)]
792        {
793            let max_len = Self::safe_len(&(self..=Self::max_value()));
794            assert!(
795                UIntPlusOne::zero() < b && b <= max_len,
796                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
797            );
798        }
799
800        let UIntPlusOne::UInt(b) = b else {
801            if self == Self::min_value() {
802                return Self::max_value();
803            }
804            // This is only reached in release builds.
805            let max_len = Self::safe_len(&(self..=Self::max_value()));
806            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
807        };
808        // If b is in range, two’s-complement wrap-around yields the correct inclusive end even if the add overflows
809        u128::from(self).wrapping_add(b - 1).into()
810    }
811
812    /// Computes the inclusive start of a range ending at `self` with length `b`,
813    /// by returning `self - (b - 1)`.
814    ///
815    /// # Panics
816    /// In debug builds, panics if `b` is zero or too large to compute a valid result.
817    /// In release builds, this will either panic or wrap on overflow; the result may be meaningless,
818    /// but it is always defined and safe (never causes undefined behavior).
819    #[allow(clippy::cast_possible_wrap)]
820    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
821        #[cfg(debug_assertions)]
822        {
823            let max_len = Self::safe_len(&(Self::min_value()..=self));
824            assert!(
825                UIntPlusOne::zero() < b && b <= max_len,
826                "b must be in range 1..=max_len (b = {b}, max_len = {max_len})"
827            );
828        }
829
830        let UIntPlusOne::UInt(b) = b else {
831            if self == Self::max_value() {
832                return Self::min_value();
833            }
834            // This is only reached in release builds.
835            let max_len = Self::safe_len(&(Self::min_value()..=self));
836            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
837        };
838
839        // If b is in range, two’s-complement wrap-around yields the correct inclusive start even if the subtraction overflows
840        u128::from(self).wrapping_sub(b - 1).into()
841    }
842}
843
844// all inclusive
845const SURROGATE_START: u32 = 0xD800;
846const SURROGATE_END: u32 = 0xDFFF;
847
848impl Integer for char {
849    // in general, the length of a 32-bit inclusive range does not fit in a u32,
850    // but unicode doesn't use the full range, so it does fit
851    type SafeLen = u32;
852
853    #[inline]
854    fn checked_add_one(self) -> Option<Self> {
855        // Can't overflow u64 because of the range of char
856        let mut num = u32::from(self) + 1;
857        // skip over the surrogate range
858        if num == SURROGATE_START {
859            num = SURROGATE_END + 1;
860        }
861        // Will report char overflow as None
862        Self::from_u32(num)
863    }
864
865    #[inline]
866    fn add_one(self) -> Self {
867        self.checked_add_one().map_or_else(
868            || {
869                panic!("char overflow"); // Panics in both debug and release modes
870            },
871            |next| next,
872        )
873    }
874
875    #[inline]
876    fn sub_one(self) -> Self {
877        let mut num = u32::from(self).wrapping_sub(1);
878        if num == SURROGATE_END {
879            num = SURROGATE_START - 1;
880        }
881        Self::from_u32(num).expect("sub_one: underflow or invalid char (e.g., called on '\\u{0}')")
882    }
883
884    #[inline]
885    fn assign_sub_one(&mut self) {
886        *self = self.sub_one();
887    }
888
889    #[inline]
890    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
891        range.next()
892    }
893
894    #[inline]
895    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
896        range.next_back()
897    }
898
899    #[inline]
900    fn min_value() -> Self {
901        '\u{0}'
902    }
903
904    #[inline]
905    fn max_value() -> Self {
906        '\u{10FFFF}'
907    }
908
909    #[cfg(feature = "from_slice")]
910    #[inline]
911    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
912        RangeSetBlaze::from_iter(slice.as_ref())
913    }
914
915    fn safe_len(r: &RangeInclusive<Self>) -> <Self as Integer>::SafeLen {
916        // assume valid, non-empty range
917        let start_num = u32::from(*r.start());
918        let end_num = u32::from(*r.end());
919        let mut len = (end_num - start_num) as <Self as Integer>::SafeLen + 1;
920        if start_num < SURROGATE_START && SURROGATE_END < end_num {
921            len -= (SURROGATE_END - SURROGATE_START + 1) as <Self as Integer>::SafeLen;
922        }
923        len
924    }
925
926    #[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
927    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
928        len as f64
929    }
930
931    #[allow(clippy::cast_possible_truncation)]
932    #[allow(clippy::cast_sign_loss)]
933    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
934        f as Self::SafeLen
935    }
936
937    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
938        fn private_panic(a: char, b: u32) -> ! {
939            let max_len = char::safe_len(&(char::MIN..=a));
940            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
941        }
942
943        let Some(b_minus_one) = b.checked_sub(1) else {
944            private_panic(self, b);
945        };
946
947        let a = u32::from(self);
948        let Some(mut num) = a.checked_add(b_minus_one) else {
949            private_panic(self, b);
950        };
951        if a < SURROGATE_START && SURROGATE_START <= num {
952            let Some(num2) = num.checked_add(SURROGATE_END - SURROGATE_START + 1) else {
953                private_panic(self, b);
954            };
955            num = num2;
956        }
957
958        let Some(result) = Self::from_u32(num) else {
959            private_panic(self, b);
960        };
961        result
962    }
963
964    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
965        fn private_panic(a: char, b: u32) -> ! {
966            let max_len = char::safe_len(&(char::MIN..=a));
967            panic!("b must be in range 1..=max_len (b = {b}, max_len = {max_len})");
968        }
969
970        let Some(b_minus_one) = b.checked_sub(1) else {
971            private_panic(self, b);
972        };
973
974        let a = u32::from(self);
975        let Some(mut num) = a.checked_sub(b_minus_one) else {
976            private_panic(self, b);
977        };
978        if num <= SURROGATE_END && SURROGATE_END < a {
979            let Some(num2) = num.checked_sub(SURROGATE_END - SURROGATE_START + 1) else {
980                private_panic(self, b);
981            };
982            num = num2;
983        }
984
985        Self::from_u32(num).expect("Real Assert: Impossible for this to fail")
986    }
987}
988
989#[cfg(test)]
990mod tests {
991    use super::*;
992    use crate::prelude::*;
993    use num_traits::{One, Zero};
994    use syntactic_for::syntactic_for;
995
996    use wasm_bindgen_test::*;
997    wasm_bindgen_test_configure!(run_in_browser);
998
999    #[test]
1000    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1001    fn coverage_integer() {
1002        let mut a = 0u8..=0u8;
1003        assert_eq!(u8::range_next_back(&mut a), Some(0));
1004        assert_eq!(u8::range_next(&mut a), None);
1005
1006        let mut b = 0i128..=0i128;
1007        assert_eq!(i128::range_next_back(&mut b), Some(0));
1008        assert_eq!(i128::range_next(&mut b), None);
1009
1010        let mut b = 0i128;
1011        i128::assign_sub_one(&mut b);
1012        assert_eq!(b, -1);
1013
1014        // convert  UIntPlusOne::MaxPlusOne to f64 and back
1015        let f = i128::safe_len_to_f64_lossy(UIntPlusOne::MaxPlusOne);
1016        let i = i128::f64_to_safe_len_lossy(f);
1017        assert_eq!(i, UIntPlusOne::MaxPlusOne);
1018
1019        let mut b = 0u128..=0u128;
1020        assert_eq!(u128::range_next_back(&mut b), Some(0));
1021        assert_eq!(u128::range_next(&mut b), None);
1022
1023        let mut b = 1u128;
1024        u128::assign_sub_one(&mut b);
1025        assert_eq!(b, 0);
1026
1027        // convert  UIntPlusOne::MaxPlusOne to f64 and back
1028        let f = u128::safe_len_to_f64_lossy(UIntPlusOne::MaxPlusOne);
1029        let i = u128::f64_to_safe_len_lossy(f);
1030        assert_eq!(i, UIntPlusOne::MaxPlusOne);
1031    }
1032
1033    #[test]
1034    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1035    #[should_panic(expected = "1")]
1036    #[cfg(debug_assertions)] // Only run this test in debug mode
1037    fn test_add_len_less_one_with_max_plus_one() {
1038        let value: i128 = 100;
1039        let len = UIntPlusOne::MaxPlusOne;
1040        let _ = value.inclusive_end_from_start(len); // This should panic in debug mode
1041    }
1042
1043    #[test]
1044    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1045    #[should_panic(expected = "2")]
1046    #[cfg(debug_assertions)] // Only run this test in debug mode
1047    fn test_sub_len_less_one_with_max_plus_one() {
1048        let value: i128 = 100;
1049        let len = UIntPlusOne::MaxPlusOne;
1050        let _ = value.start_from_inclusive_end(len); // This should panic in debug mode
1051    }
1052
1053    #[test]
1054    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1055    #[allow(clippy::cognitive_complexity, clippy::legacy_numeric_constants)]
1056    fn test_ipv4_and_ipv6_etc() {
1057        syntactic_for! { ty in [char, Ipv6Addr, u128, i128, Ipv4Addr] {
1058            $(
1059            // Test the minimum value for the type
1060            let a = <$ty>::min_value();
1061            let b = a.checked_add_one();
1062            assert_eq!(b, Some(<$ty>::min_value().add_one()));
1063
1064            // Show overflow behavior
1065            let a = <$ty>::max_value();
1066            let b = a.checked_add_one();
1067            assert_eq!(b, None);
1068
1069            let a = <$ty>::min_value();
1070            let mut b = a.add_one();
1071            assert_eq!(b, <$ty>::min_value().add_one());
1072
1073            let c = b.sub_one();
1074            assert_eq!(c, a);
1075
1076            b.assign_sub_one();
1077            assert_eq!(b, a);
1078
1079            let mut a = <$ty>::min_value()..=<$ty>::min_value();
1080            let b = <$ty>::range_next(&mut a);
1081            assert_eq!(b, Some(<$ty>::min_value()));
1082            let b = <$ty>::range_next(&mut a);
1083            assert_eq!(b, None);
1084
1085            let mut a = <$ty>::min_value()..=<$ty>::max_value();
1086            let b = <$ty>::range_next_back(&mut a);
1087            assert_eq!(b, Some(<$ty>::max_value()));
1088
1089            assert_eq!(<$ty>::min_value(), <$ty>::min_value());
1090
1091            let universe = <$ty>::min_value()..=<$ty>::max_value();
1092            let len = <$ty>::safe_len(&universe);
1093            assert_eq!(len, <$ty>::safe_len(&(<$ty>::min_value()..=<$ty>::max_value())));
1094
1095            let len_via_f64 = <$ty>::f64_to_safe_len_lossy(<$ty>::safe_len_to_f64_lossy(len));
1096            assert_eq!(len, len_via_f64);
1097
1098            let short = <$ty>::min_value()..=<$ty>::min_value();
1099            let len = <$ty>::safe_len(&short);
1100            let len_via_f64 = <$ty>::f64_to_safe_len_lossy(<$ty>::safe_len_to_f64_lossy(len));
1101            assert_eq!(len, len_via_f64);
1102
1103            let len = <$ty>::safe_len(&universe);
1104            let b = <$ty>::min_value().inclusive_end_from_start(len);
1105            assert_eq!(b, <$ty>::max_value());
1106
1107            let c = b.start_from_inclusive_end(len);
1108            assert_eq!(c, <$ty>::min_value());
1109
1110            let range = <$ty>::min_value()..=<$ty>::min_value().add_one();
1111            let len2 = <$ty>::safe_len(&range);
1112            let b = <$ty>::min_value().inclusive_end_from_start(len2);
1113            assert_eq!(b, <$ty>::min_value().add_one());
1114
1115            let b = <$ty>::max_value().start_from_inclusive_end(len2);
1116            assert_eq!(b, <$ty>::max_value().sub_one());
1117
1118            #[cfg(feature = "from_slice")]
1119            {
1120                let range_set_blaze = <$ty>::from_slice(&[<$ty>::min_value()]);
1121                assert_eq!(range_set_blaze, RangeSetBlaze::from_iter([<$ty>::min_value()]));
1122            }
1123            )*
1124        }}
1125    }
1126
1127    #[test]
1128    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1129    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1130    #[allow(clippy::legacy_numeric_constants)]
1131    fn test_i128_overflow() {
1132        let value: i128 = i128::max_value();
1133        let _ = value.inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1134    }
1135
1136    #[test]
1137    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1138    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1139    #[allow(clippy::legacy_numeric_constants)]
1140    fn test_i128_underflow() {
1141        let value: i128 = i128::min_value();
1142        let _ = value.start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1143    }
1144
1145    #[test]
1146    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1147    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1148    #[allow(clippy::legacy_numeric_constants)]
1149    fn test_u128_overflow() {
1150        let value: u128 = u128::max_value();
1151        let _ = value.inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1152    }
1153
1154    #[test]
1155    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1156    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1157    #[allow(clippy::legacy_numeric_constants)]
1158    fn test_u128_underflow() {
1159        let value: u128 = u128::min_value();
1160        let _ = value.start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1161    }
1162
1163    #[test]
1164    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1165    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1166    #[allow(clippy::legacy_numeric_constants)]
1167    fn test_ipv6_overflow() {
1168        let value: Ipv6Addr = Ipv6Addr::max_value();
1169        let _ = value.inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1170    }
1171
1172    #[test]
1173    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1174    #[should_panic(expected = "char overflow")]
1175    #[allow(clippy::legacy_numeric_constants)]
1176    fn test_char0_overflow() {
1177        let value: char = char::max_value();
1178        let _ = value.add_one();
1179    }
1180
1181    #[test]
1182    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1183    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1112064)")]
1184    #[allow(clippy::legacy_numeric_constants)]
1185    fn test_char1_overflow() {
1186        let value: char = char::max_value();
1187        let len2 = char::safe_len(&(char::min_value()..=char::min_value().add_one()));
1188        let _ = value.inclusive_end_from_start(len2);
1189    }
1190
1191    #[test]
1192    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1193    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1194    #[allow(clippy::legacy_numeric_constants)]
1195    fn test_char1_underflow() {
1196        let value: char = char::min_value();
1197        let len2 = char::safe_len(&(char::min_value()..=char::min_value().add_one()));
1198        let _ = value.start_from_inclusive_end(len2);
1199    }
1200
1201    #[test]
1202    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1203    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1204    fn test_ipv6_underflow() {
1205        let value: Ipv6Addr = Ipv6Addr::min_value();
1206        let _ = value.start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1207    }
1208
1209    #[test]
1210    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1211    #[allow(clippy::cognitive_complexity)]
1212    fn test_char() {
1213        // This loops over 1 million characters, but it seems fast enough.
1214        // Define the universe as the complement of an empty RangeSetBlaze
1215        let universe = !RangeSetBlaze::<char>::default();
1216
1217        // Check add_one and sub_one behavior
1218        let max_value = <char as Integer>::max_value();
1219        assert_eq!(max_value.checked_add_one(), None);
1220
1221        let mut prev = None;
1222        let mut len = <char as Integer>::SafeLen::zero();
1223        for item in <char as Integer>::min_value()..=max_value {
1224            let len2b = <char as Integer>::safe_len(&(item..=max_value));
1225            let mut expected = universe.len();
1226            expected -= len;
1227            assert_eq!(len2b, expected);
1228
1229            let item2 = max_value.start_from_inclusive_end(len2b);
1230            assert_eq!(item2, item);
1231
1232            let item3 = item2.inclusive_end_from_start(len2b);
1233            assert_eq!(item3, max_value);
1234
1235            len += <char as Integer>::SafeLen::one();
1236            let len2 = <char as Integer>::safe_len(&(<char as Integer>::min_value()..=item));
1237            assert_eq!(len, len2);
1238            assert_eq!(
1239                len2,
1240                <char as Integer>::f64_to_safe_len_lossy(<char as Integer>::safe_len_to_f64_lossy(
1241                    len2
1242                ))
1243            );
1244
1245            let item2 = <char as Integer>::min_value().inclusive_end_from_start(len);
1246            assert_eq!(item2, item);
1247
1248            let item3 = item.start_from_inclusive_end(len);
1249            assert_eq!(item3, <char as Integer>::min_value());
1250
1251            if let Some(prev) = prev {
1252                assert!(universe.contains(prev));
1253                assert!(universe.contains(item));
1254                assert!(universe.is_superset(&RangeSetBlaze::from_iter([prev..=item])));
1255
1256                assert_eq!(prev.checked_add_one(), Some(item));
1257                assert_eq!(prev.add_one(), item);
1258
1259                assert_eq!(item.sub_one(), prev);
1260                let mut item2 = item;
1261                item2.assign_sub_one();
1262                assert_eq!(item2, prev);
1263            }
1264
1265            prev = Some(item);
1266        }
1267        assert_eq!(universe.len(), len);
1268
1269        // Additional checks can be added here if needed for coverage
1270    }
1271
1272    #[test]
1273    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1274    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 66)")]
1275    fn test_add_len_less_one_panic_conditions1() {
1276        // Case 1: `b.checked_sub(1)` returns `None`
1277        let character = 'A';
1278        let b = 0;
1279        _ = character.inclusive_end_from_start(b); // This should panic due to overflow
1280    }
1281
1282    #[test]
1283    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1284    #[should_panic(expected = "b must be in range 1..=max_len (b = 3, max_len = 1112064)")]
1285    fn test_add_len_less_one_panic_conditions2() {
1286        // Case 2: `self.checked_add(b_less_one)` returns `None`
1287        let character = char::MAX;
1288        let b = 3;
1289        _ = character.inclusive_end_from_start(b); // This should panic due to overflow
1290    }
1291
1292    #[test]
1293    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1294    #[should_panic(expected = "b must be in range 1..=max_len (b = 4294967295, max_len = 66)")]
1295    fn test_add_len_less_one_panic_conditions3() {
1296        // Case 3: overflow when adding `b - 1` to `self`
1297        let character = 'A';
1298        let b = u32::MAX;
1299        _ = character.inclusive_end_from_start(b); // This should panic due to overflow
1300    }
1301
1302    #[test]
1303    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1304    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 66)")]
1305    fn test_sub_len_less_one_panic_conditions1() {
1306        // Case 1: `b.checked_sub(1)` fails, causing an immediate panic.
1307        let character = 'A';
1308        let b = 0;
1309        _ = character.start_from_inclusive_end(b); // This should panic due to underflow
1310    }
1311
1312    #[test]
1313    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1314    #[should_panic(expected = "b must be in range 1..=max_len (b = 4294967295, max_len = 66)")]
1315    fn test_sub_len_less_one_panic_conditions2() {
1316        // Case 2: `a.checked_sub(b_less_one)` fails, causing underflow.
1317        let character = 'A';
1318        let b = u32::MAX;
1319        _ = character.start_from_inclusive_end(b); // This should panic due to underflow
1320    }
1321
1322    #[allow(clippy::legacy_numeric_constants, clippy::cognitive_complexity)]
1323    #[test]
1324    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1325    fn test_use_of_as_00() {
1326        syntactic_for! { ty in [char, i8, i16, i32, i64, i128, isize, Ipv4Addr, Ipv6Addr, u8, u16, u32, u64, u128, usize] {
1327            $(
1328        let a = <$ty>::min_value();
1329        let b = <$ty>::max_value();
1330        let len = <$ty>::safe_len(&(a..=b));
1331        assert_eq!(<$ty>::inclusive_end_from_start(a, len), b);
1332        assert_eq!(<$ty>::start_from_inclusive_end(b, len), a);
1333            )*
1334        }}
1335    }
1336
1337    #[cfg(debug_assertions)]
1338    #[test]
1339    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1340    fn test_use_of_as_01() {
1341        let _ = 127i8.inclusive_end_from_start(0);
1342    }
1343
1344    #[cfg(not(debug_assertions))]
1345    #[test]
1346    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1347    fn test_use_of_as_02() {
1348        assert_eq!(127i8.inclusive_end_from_start(0), 126);
1349        assert_eq!(127i8.start_from_inclusive_end(0), -128);
1350        assert_eq!(127i8.inclusive_end_from_start(2), -128);
1351        assert_eq!((-126i8).start_from_inclusive_end(4), 127);
1352    }
1353
1354    #[cfg(debug_assertions)]
1355    #[test]
1356    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 256)")]
1357    fn test_use_of_as_03() {
1358        let _ = 127i8.start_from_inclusive_end(0);
1359    }
1360
1361    #[cfg(debug_assertions)]
1362    #[test]
1363    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1364    fn test_use_of_as_04() {
1365        let _ = 127i8.inclusive_end_from_start(2);
1366    }
1367
1368    #[cfg(debug_assertions)]
1369    #[test]
1370    #[should_panic(expected = "b must be in range 1..=max_len (b = 4, max_len = 3)")]
1371    fn test_use_of_as_05() {
1372        let _ = (-126i8).start_from_inclusive_end(4);
1373    }
1374
1375    #[test]
1376    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1377    fn test_use_of_as_06() {
1378        for a in (-128i8)..=127i8 {
1379            let b = i8::safe_len(&(a..=127i8));
1380            assert_eq!(a.inclusive_end_from_start(b), 127i8);
1381            let b = i8::safe_len(&(i8::MIN..=a));
1382            assert_eq!(a.start_from_inclusive_end(b), -128i8);
1383        }
1384    }
1385
1386    // make full tests for i128
1387    #[cfg(debug_assertions)]
1388    #[test]
1389    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1390    fn test_use_of_as_11() {
1391        let _ = i128::MAX.inclusive_end_from_start(UIntPlusOne::zero());
1392    }
1393
1394    #[cfg(not(debug_assertions))]
1395    #[test]
1396    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1397    fn test_use_of_as_12() {
1398        assert_eq!(
1399            i128::MAX.inclusive_end_from_start(UIntPlusOne::zero()),
1400            170141183460469231731687303715884105726
1401        );
1402        assert_eq!(
1403            i128::MAX.start_from_inclusive_end(UIntPlusOne::zero()),
1404            -170141183460469231731687303715884105728
1405        );
1406        assert_eq!(
1407            i128::MAX.inclusive_end_from_start(UIntPlusOne::UInt(2)),
1408            -170141183460469231731687303715884105728
1409        );
1410        assert_eq!(
1411            (i128::MIN).start_from_inclusive_end(UIntPlusOne::UInt(2)),
1412            170141183460469231731687303715884105727
1413        );
1414    }
1415
1416    #[cfg(debug_assertions)]
1417    #[test]
1418    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = (u128::MAX + 1)")]
1419    fn test_use_of_as_13() {
1420        let _ = i128::MAX.start_from_inclusive_end(UIntPlusOne::zero());
1421    }
1422
1423    #[cfg(debug_assertions)]
1424    #[test]
1425    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1426    fn test_use_of_as_14() {
1427        let _ = i128::MAX.inclusive_end_from_start(UIntPlusOne::UInt(2));
1428    }
1429
1430    #[cfg(debug_assertions)]
1431    #[test]
1432    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1433    fn test_use_of_as_15() {
1434        let _ = (i128::MIN).start_from_inclusive_end(UIntPlusOne::UInt(2));
1435    }
1436
1437    #[test]
1438    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1439    fn test_use_of_as_16() {
1440        assert_eq!(
1441            (i128::MIN).inclusive_end_from_start(UIntPlusOne::MaxPlusOne),
1442            i128::MAX
1443        );
1444        assert_eq!(
1445            (i128::MAX).start_from_inclusive_end(UIntPlusOne::MaxPlusOne),
1446            i128::MIN
1447        );
1448    }
1449
1450    #[test]
1451    #[should_panic(
1452        expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 170141183460469231731687303715884105728)"
1453    )]
1454    fn test_use_of_as_17() {
1455        let _ = (0i128).inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1456    }
1457
1458    #[test]
1459    #[should_panic(
1460        expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 170141183460469231731687303715884105729)"
1461    )]
1462    fn test_use_of_as_18() {
1463        let _ = (0i128).start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1464    }
1465
1466    // make full tests for u128
1467    #[cfg(debug_assertions)]
1468    #[test]
1469    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1470    fn test_use_of_as_21() {
1471        let _ = u128::MAX.inclusive_end_from_start(UIntPlusOne::zero());
1472    }
1473
1474    #[cfg(not(debug_assertions))]
1475    #[test]
1476    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1477    fn test_use_of_as_22() {
1478        assert_eq!(
1479            u128::MAX.inclusive_end_from_start(UIntPlusOne::zero()),
1480            340282366920938463463374607431768211454
1481        );
1482        assert_eq!(u128::MAX.start_from_inclusive_end(UIntPlusOne::zero()), 0);
1483        assert_eq!(u128::MAX.inclusive_end_from_start(UIntPlusOne::UInt(2)), 0);
1484        assert_eq!(
1485            (u128::MIN).start_from_inclusive_end(UIntPlusOne::UInt(2)),
1486            340282366920938463463374607431768211455
1487        );
1488    }
1489
1490    #[cfg(debug_assertions)]
1491    #[test]
1492    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = (u128::MAX + 1)")]
1493    fn test_use_of_as_23() {
1494        let _ = u128::MAX.start_from_inclusive_end(UIntPlusOne::zero());
1495    }
1496
1497    #[cfg(debug_assertions)]
1498    #[test]
1499    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1500    fn test_use_of_as_24() {
1501        let _ = u128::MAX.inclusive_end_from_start(UIntPlusOne::UInt(2));
1502    }
1503
1504    #[cfg(debug_assertions)]
1505    #[test]
1506    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1507    fn test_use_of_as_25() {
1508        let _ = (u128::MIN).start_from_inclusive_end(UIntPlusOne::UInt(2));
1509    }
1510
1511    #[test]
1512    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1513    fn test_use_of_as_26() {
1514        assert_eq!(
1515            (u128::MIN).inclusive_end_from_start(UIntPlusOne::MaxPlusOne),
1516            u128::MAX
1517        );
1518        assert_eq!(
1519            (u128::MAX).start_from_inclusive_end(UIntPlusOne::MaxPlusOne),
1520            u128::MIN
1521        );
1522    }
1523
1524    #[test]
1525    #[should_panic(
1526        expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 340282366920938463463374607431768211454)"
1527    )]
1528    fn test_use_of_as_27() {
1529        let _ = (2u128).inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1530    }
1531
1532    #[test]
1533    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1534    fn test_use_of_as_28() {
1535        let _ = (0u128).start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1536    }
1537
1538    // make full tests for Ipv4Addr
1539    #[cfg(debug_assertions)]
1540    #[test]
1541    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1542    fn test_use_of_as_31() {
1543        let _ = Ipv4Addr::max_value().inclusive_end_from_start(0);
1544    }
1545
1546    #[cfg(not(debug_assertions))]
1547    #[test]
1548    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1549    fn test_use_of_as_32() {
1550        assert_eq!(
1551            Ipv4Addr::max_value().inclusive_end_from_start(0),
1552            Ipv4Addr::new(255, 255, 255, 254)
1553        );
1554        assert_eq!(
1555            Ipv4Addr::max_value().start_from_inclusive_end(0),
1556            Ipv4Addr::from(0)
1557        );
1558        assert_eq!(
1559            Ipv4Addr::max_value().inclusive_end_from_start(2),
1560            Ipv4Addr::from(0)
1561        );
1562        assert_eq!(
1563            Ipv4Addr::min_value().start_from_inclusive_end(2),
1564            Ipv4Addr::new(255, 255, 255, 255)
1565        );
1566        assert_eq!(
1567            Ipv4Addr::new(0, 0, 0, 2).inclusive_end_from_start(u64::MAX),
1568            Ipv4Addr::from(0)
1569        );
1570
1571        assert_eq!(
1572            Ipv4Addr::new(0, 0, 0, 0).start_from_inclusive_end(u64::MAX),
1573            Ipv4Addr::new(0, 0, 0, 2)
1574        );
1575    }
1576
1577    #[cfg(debug_assertions)]
1578    #[test]
1579    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 4294967296)")]
1580    fn test_use_of_as_33() {
1581        let _ = Ipv4Addr::max_value().start_from_inclusive_end(0);
1582    }
1583
1584    #[cfg(debug_assertions)]
1585    #[test]
1586    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1587    fn test_use_of_as_34() {
1588        let _ = Ipv4Addr::max_value().inclusive_end_from_start(2);
1589    }
1590
1591    #[cfg(debug_assertions)]
1592    #[test]
1593    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1594    fn test_use_of_as_35() {
1595        let _ = (Ipv4Addr::min_value()).start_from_inclusive_end(2);
1596    }
1597
1598    // ipv6
1599
1600    #[cfg(debug_assertions)]
1601    #[test]
1602    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1)")]
1603    fn test_use_of_as_41() {
1604        let _ = Ipv6Addr::max_value().inclusive_end_from_start(UIntPlusOne::zero());
1605    }
1606
1607    #[cfg(not(debug_assertions))]
1608    #[test]
1609    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1610    fn test_use_of_as_42() {
1611        assert_eq!(
1612            Ipv6Addr::max_value().inclusive_end_from_start(UIntPlusOne::zero()),
1613            Ipv6Addr::from(340282366920938463463374607431768211454)
1614        );
1615        assert_eq!(
1616            Ipv6Addr::max_value().start_from_inclusive_end(UIntPlusOne::zero()),
1617            Ipv6Addr::from(0)
1618        );
1619        assert_eq!(
1620            Ipv6Addr::max_value().inclusive_end_from_start(UIntPlusOne::UInt(2)),
1621            Ipv6Addr::from(0)
1622        );
1623        assert_eq!(
1624            (Ipv6Addr::min_value()).start_from_inclusive_end(UIntPlusOne::UInt(2)),
1625            Ipv6Addr::from(340282366920938463463374607431768211455)
1626        );
1627    }
1628
1629    #[cfg(debug_assertions)]
1630    #[test]
1631    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = (u128::MAX + 1)")]
1632    fn test_use_of_as_43() {
1633        let _ = Ipv6Addr::max_value().start_from_inclusive_end(UIntPlusOne::zero());
1634    }
1635
1636    #[cfg(debug_assertions)]
1637    #[test]
1638    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1639    fn test_use_of_as_44() {
1640        let _ = Ipv6Addr::max_value().inclusive_end_from_start(UIntPlusOne::UInt(2));
1641    }
1642
1643    #[cfg(debug_assertions)]
1644    #[test]
1645    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1646    fn test_use_of_as_45() {
1647        let _ = (Ipv6Addr::min_value()).start_from_inclusive_end(UIntPlusOne::UInt(2));
1648    }
1649
1650    #[test]
1651    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1652    fn test_use_of_as_46() {
1653        assert_eq!(
1654            (Ipv6Addr::min_value()).inclusive_end_from_start(UIntPlusOne::MaxPlusOne),
1655            Ipv6Addr::max_value()
1656        );
1657        assert_eq!(
1658            (Ipv6Addr::max_value()).start_from_inclusive_end(UIntPlusOne::MaxPlusOne),
1659            Ipv6Addr::min_value()
1660        );
1661    }
1662
1663    #[test]
1664    #[should_panic(
1665        expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 340282366920938463463374607431768211454)"
1666    )]
1667    fn test_use_of_as_47() {
1668        let _ = Ipv6Addr::from(2u128).inclusive_end_from_start(UIntPlusOne::MaxPlusOne);
1669    }
1670
1671    #[test]
1672    #[should_panic(expected = "b must be in range 1..=max_len (b = (u128::MAX + 1, max_len = 1)")]
1673    fn test_use_of_as_48() {
1674        let _ = Ipv6Addr::from(0u128).start_from_inclusive_end(UIntPlusOne::MaxPlusOne);
1675    }
1676
1677    // char
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_51() {
1682        let _ = char::max_value().inclusive_end_from_start(0);
1683    }
1684
1685    #[test]
1686    #[should_panic(expected = "b must be in range 1..=max_len (b = 0, max_len = 1112064)")]
1687    fn test_use_of_as_53() {
1688        let _ = char::max_value().start_from_inclusive_end(0);
1689    }
1690
1691    #[test]
1692    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1112064)")]
1693    fn test_use_of_as_54() {
1694        let _ = char::max_value().inclusive_end_from_start(2);
1695    }
1696
1697    #[test]
1698    #[should_panic(expected = "b must be in range 1..=max_len (b = 2, max_len = 1)")]
1699    fn test_use_of_as_55() {
1700        let _ = (char::min_value()).start_from_inclusive_end(2);
1701    }
1702
1703    #[test]
1704    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1705    fn test_use_of_as_56() {
1706        assert_eq!(
1707            (char::min_value()).inclusive_end_from_start(1_112_064),
1708            char::max_value()
1709        );
1710        assert_eq!(
1711            (char::max_value()).start_from_inclusive_end(1_112_064),
1712            char::min_value()
1713        );
1714    }
1715
1716    #[test]
1717    #[should_panic(expected = "b must be in range 1..=max_len (b = 1112064, max_len = 3)")]
1718    fn test_use_of_as_57() {
1719        let _ = '\x02'.inclusive_end_from_start(1_112_064);
1720    }
1721
1722    #[test]
1723    #[should_panic(expected = "b must be in range 1..=max_len (b = 1112064, max_len = 1)")]
1724    fn test_use_of_as_58() {
1725        let _ = '\x00'.start_from_inclusive_end(1_112_064);
1726    }
1727
1728    #[test]
1729    #[cfg(debug_assertions)]
1730    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1731    #[should_panic(expected = "assertion failed: r.start() <= r.end()")]
1732    #[allow(clippy::reversed_empty_ranges)]
1733    fn test_safe_len() {
1734        let i = 0u128..=0u128;
1735        assert_eq!(u128::safe_len(&i), UIntPlusOne::UInt(1));
1736
1737        let i = 0u128..=1u128;
1738        assert_eq!(u128::safe_len(&i), UIntPlusOne::UInt(2));
1739
1740        let i = 1u128..=0u128;
1741        // This call is expected to panic due to the debug_assert in safe_len
1742        let _ = u128::safe_len(&i);
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 safe_len2() {
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_attr(target_arch = "wasm32", wasm_bindgen_test)]
1764    #[should_panic(expected = "b must be in range 1..=max_len (b = 4294911999, max_len = 55295)")]
1765    fn safe_len_char1() {
1766        let a = '\u{D7FE}';
1767        let len = 4_294_911_999u32;
1768        let _ = a.inclusive_end_from_start(len);
1769    }
1770
1771    #[test]
1772    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1773    #[should_panic(expected = "b must be in range 1..=max_len (b = 57343, max_len = 55297)")]
1774    fn safe_len_char2() {
1775        let a = '\u{E000}';
1776        let len = 0xDFFFu32;
1777        let _ = a.start_from_inclusive_end(len);
1778    }
1779}