tstr/
to_uint.rs

1mod sealed {
2    #[doc(hidden)]
3    pub trait Sealed: Sized {}
4}
5use sealed::Sealed;
6
7/// Converts a [`TStr`] to unsigned integers.
8///
9/// # Example
10///
11/// ```rust
12/// use tstr::{ToUint, TS, ts};
13///
14/// type Zero = TS!(0);
15/// type N8   = TS!(8);
16/// type N13  = TS!(13);
17/// type N15  = TS!(0xF);
18/// type N16  = TS!(0b10000);
19///
20/// assert_eq!(Zero::USIZE, 0);
21/// assert_eq!(N8::USIZE, 8);
22/// assert_eq!(N13::USIZE, 13);
23/// assert_eq!(N15::USIZE, 15);
24/// assert_eq!(N16::USIZE, 16);
25///
26/// assert_eq!(ts!(0).to_u128(), 0);
27/// assert_eq!(ts!(8).to_u128(), 8);
28/// assert_eq!(ts!(13).to_u128(), 13);
29/// assert_eq!(ts!(0xF).to_u128(), 15);
30/// assert_eq!(ts!(0b10000).to_u128(), 16);
31///
32/// ```
33///
34/// [`TStr`]: ./struct.TStr.html
35pub trait ToUint: Sized {
36    /// The `usize` value of the type.
37    ///
38    /// By default this value is a saturated cast from `Self::U128`.
39    const USIZE: usize = u128_as_usize(Self::U128);
40
41    /// The `u128` value of the type.
42    const U128: u128;
43
44    #[doc(hidden)]
45    const DIGITS: u32;
46
47    /// Gets the usize value of this type
48    ///
49    /// By default this value is a saturated cast from `Self::U128`.
50    fn to_usize(&self) -> usize {
51        Self::USIZE
52    }
53
54    /// Gets the u128 value of this type
55    fn to_u128(&self) -> u128 {
56        Self::U128
57    }
58}
59
60#[cfg(feature = "const_generics")]
61macro_rules! impl_for_const {
62    () => {
63        const fn str_to_u128(s: &str) -> u128 {
64            let s = s.as_bytes();
65            let mut out = 0u128;
66            let mut index = 0usize;
67
68            while index < s.len() {
69                let digit = s[index];
70
71                // This has the effect of panicking on non to '0' to '9' characters.
72                #[allow(clippy::no_effect)]
73                ["Expected all characters to be digits"]
74                    [!(b'0' <= digit && digit <= b'9') as usize];
75
76                let digit = (digit - b'0') as u128;
77                out = out * 10 + digit;
78
79                index += 1;
80            }
81            out
82        }
83
84        impl<const N: &'static str> Sealed for crate::___<N> {}
85
86        impl<const N: &'static str> ToUint for crate::___<N> {
87            const U128: u128 = str_to_u128(N);
88            const DIGITS: u32 = N.len() as u32;
89        }
90    };
91}
92
93impl<T> Sealed for crate::TStr<T> where T: Sealed {}
94
95impl<T> ToUint for crate::TStr<T>
96where
97    T: ToUint,
98{
99    // Intentionally not setting this.
100    // const USIZE: usize = T::USIZE;
101    const U128: u128 = T::U128;
102    const DIGITS: u32 = T::DIGITS;
103}
104
105#[cfg(feature = "const_generics")]
106impl_for_const! {}
107
108#[cfg(not(feature = "const_generics"))]
109mod impl_no_const_generics;
110
111const fn u128_as_usize(n: u128) -> usize {
112    const MAXU: u128 = usize::max_value() as u128;
113    [n, MAXU][(n > MAXU) as usize] as usize
114}