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