1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
#![doc = include_str!("../README.md")]
#![cfg_attr(not(any(doc, test, doctest, feature = "std")), no_std)]
#![cfg_attr(any(doc, test, doctest, feature = "unchecked_math"), feature(unchecked_math))]

use include_display_mode_tex::include_display_mode_tex;

/// [Newtype](https://doc.rust-lang.org/rust-by-example/generics/new_types.html) offering some utility methods
/// for [zero-based indices](https://en.wikipedia.org/wiki/Zero-based_numbering)
pub struct ZeroBasedIndex<T>(pub T);

impl ZeroBasedIndex<usize> {
    /// If the [cardinality](https://en.wikipedia.org/wiki/Cardinality) of the
    /// [closed](https://en.wikipedia.org/wiki/Interval_(mathematics)#Classification_of_intervals)
    /// [integer interval](https://en.wikipedia.org/wiki/Interval_(mathematics)#Integer_intervals)
    /// from 0 to the stored value fits into [usize][core::primitive::usize], returns that cardinality
    /// as `Some` variant of [Option][core::option::Option]<[usize][core::primitive::usize]>. Otherwise (when
    /// happens [integer overflow](https://en.wikipedia.org/wiki/Integer_overflow)),
    /// the returned value is `None`.
    ///
    /// Using mathematical notation,
    ///
    #[doc = include_display_mode_tex!("./tex/try_get_len_of_closed_int_intvl_from_0.tex")]
    ///
    /// # Examples
    ///
    /// ## Base case
    /// ```
    /// use zero_based_index::ZeroBasedIndex;
    ///
    /// let zbi = ZeroBasedIndex::<usize>(2);
    /// assert_eq!(zbi.try_get_len_of_closed_int_intvl_from_0(), Some(3));
    /// ```
    ///
    /// ## Corner case
    ///
    /// ```
    /// use zero_based_index::ZeroBasedIndex;
    ///
    /// let zbi = ZeroBasedIndex::<usize>(usize::MAX);
    /// assert_eq!(zbi.try_get_len_of_closed_int_intvl_from_0(), None);
    /// ```
    pub const fn try_get_len_of_closed_int_intvl_from_0(&self) -> Option<usize> {
        // [0..r] = {0} ∪ (0..r]
        // |[0..r]| = |{0}| + |(0..r]|
        // |{0}| = 1
        // |(0..r]| = |[1..r]| = r
        // |[0..r]| = r + 1
        self.0.checked_add(1)
    }

    /// Assuming the [cardinality](https://en.wikipedia.org/wiki/Cardinality) of the
    /// [closed](https://en.wikipedia.org/wiki/Interval_(mathematics)#Classification_of_intervals)
    /// [integer interval](https://en.wikipedia.org/wiki/Interval_(mathematics)#Integer_intervals)
    /// from 0 to the stored value fits into [usize][core::primitive::usize], returns that cardinality
    /// as [usize][core::primitive::usize].
    ///
    /// Using mathematical notation,
    ///
    #[doc = include_display_mode_tex!("./tex/try_get_len_of_closed_int_intvl_from_0.tex")]
    ///
    /// # Safety
    ///
    /// This results in undefined behavior when intuitively (or, rather, naively)
    /// `self.0 + 1 > usize::MAX`,
    /// i.e. when [checked_add][core::primitive::usize::checked_add] would return `None`
    /// for `(self.0, 1)`.
    ///
    /// # Examples
    ///
    /// ## Base case
    /// ```
    /// use zero_based_index::ZeroBasedIndex;
    ///
    /// let zbi = ZeroBasedIndex::<usize>(2);
    /// // <Proof of the necessary level of rigor that the overflow will never happen>
    /// assert_eq!(unsafe { zbi.get_len_of_closed_int_intvl_from_0_ignoring_overflow() }, 3);
    /// ```
    ///
    /// ## Corner case
    ///
    /// The following is [**UB (Undefined Behavior)**](https://en.wikipedia.org/wiki/Undefined_behavior):
    ///
    /// ```no_run
    /// use zero_based_index::ZeroBasedIndex;
    ///
    /// let zbi = ZeroBasedIndex::<usize>(usize::MAX);
    /// // Undefined Behavior can even summon nasal demons that will take your sinful soul.
    /// assert_eq!(unsafe { zbi.get_len_of_closed_int_intvl_from_0_ignoring_overflow() }, 666);
    /// ```    
    ///
    /// *This function is available only if `zero_based_index` is built with the `"unchecked_math"` feature.*
    #[cfg(any(doc, test, doctest, feature = "unchecked_math"))]
    pub unsafe fn get_len_of_closed_int_intvl_from_0_ignoring_overflow(&self) -> usize {
        self.0.unchecked_add(1)
    }
}

/// Convenience trait for working with zero-based indices, notably of type `usize`
pub trait AsZeroBasedIndex: Sized {
    fn as_zero_based_index(self) -> ZeroBasedIndex<Self>;
}

impl AsZeroBasedIndex for usize {
    fn as_zero_based_index(self) -> ZeroBasedIndex<Self> {
        ZeroBasedIndex(self)
    }
}