small_fixed_array/
length.rs

1use core::{
2    fmt::{Debug, Display},
3    num::{NonZeroU16, NonZeroU32, NonZeroU8},
4};
5
6use alloc::boxed::Box;
7
8use crate::inline::get_heap_threshold;
9
10mod sealed {
11    use core::num::{NonZeroU16, NonZeroU32, NonZeroU8};
12
13    pub trait LengthSealed {}
14    impl LengthSealed for u8 {}
15    impl LengthSealed for u16 {}
16    #[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
17    impl LengthSealed for u32 {}
18
19    pub trait NonZeroSealed {}
20    impl NonZeroSealed for NonZeroU8 {}
21    impl NonZeroSealed for NonZeroU16 {}
22    #[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
23    impl NonZeroSealed for NonZeroU32 {}
24}
25
26#[derive(Debug)]
27pub struct InvalidLength<T> {
28    type_name: &'static str,
29    original: Box<[T]>,
30}
31
32impl<T> InvalidLength<T> {
33    #[cold]
34    #[track_caller]
35    pub(crate) fn new(type_name: &'static str, original: Box<[T]>) -> Self {
36        Self {
37            type_name,
38            original,
39        }
40    }
41
42    /// Returns the original Box<[T]> that could not be converted from.
43    pub fn get_inner(self) -> Box<[T]> {
44        self.original
45    }
46}
47
48#[cfg(feature = "std")]
49impl<T: Debug> std::error::Error for InvalidLength<T> {}
50
51impl<T> core::fmt::Display for InvalidLength<T> {
52    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53        write!(
54            f,
55            "Cannot fit {} into {}",
56            self.original.len(),
57            self.type_name,
58        )
59    }
60}
61
62#[derive(Debug)]
63pub struct InvalidStrLength {
64    type_name: &'static str,
65    original: Box<str>,
66}
67
68impl InvalidStrLength {
69    /// Returns the original [`Box<str>`] that could not be converted from.
70    pub fn get_inner(self) -> Box<str> {
71        self.original
72    }
73}
74
75#[cfg(feature = "std")]
76impl std::error::Error for InvalidStrLength {}
77
78impl core::fmt::Display for InvalidStrLength {
79    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80        write!(
81            f,
82            "Cannot fit {} into {}",
83            self.original.len(),
84            self.type_name,
85        )
86    }
87}
88
89impl TryFrom<InvalidLength<u8>> for InvalidStrLength {
90    type Error = core::str::Utf8Error;
91
92    fn try_from(value: InvalidLength<u8>) -> Result<Self, Self::Error> {
93        let original = if let Err(err) = core::str::from_utf8(&value.original) {
94            return Err(err);
95        } else {
96            unsafe { alloc::str::from_boxed_utf8_unchecked(value.original) }
97        };
98
99        Ok(Self {
100            original,
101            type_name: value.type_name,
102        })
103    }
104}
105
106#[doc(hidden)]
107pub trait NonZero<Int: ValidLength>:
108    sealed::NonZeroSealed + Into<Int> + Sized + Copy + PartialEq + Debug
109{
110    #[allow(unused)]
111    fn new(val: Int) -> Option<Self>;
112}
113
114impl NonZero<u8> for NonZeroU8 {
115    fn new(val: u8) -> Option<Self> {
116        NonZeroU8::new(val)
117    }
118}
119
120impl NonZero<u16> for NonZeroU16 {
121    fn new(val: u16) -> Option<Self> {
122        NonZeroU16::new(val)
123    }
124}
125
126impl NonZero<u32> for NonZeroU32 {
127    fn new(val: u32) -> Option<Self> {
128        NonZeroU32::new(val)
129    }
130}
131
132/// A sealed trait to represent valid lengths for a [`FixedArray`].
133///
134/// This is implemented on `u32` for non-16 bit platforms, and `u16` on all platforms.
135///
136/// [`FixedArray`]: `crate::array::FixedArray`
137pub trait ValidLength:
138    sealed::LengthSealed + Copy + Display + PartialEq + From<u8> + TryFrom<usize> + Into<u32>
139{
140    const ZERO: Self;
141    const MAX: Self;
142    #[deprecated = "will be removed in the next major release"]
143    #[allow(deprecated)]
144    const DANGLING: Self::NonZero;
145
146    #[deprecated = "will be removed in the next major release"]
147    type NonZero: NonZero<Self>;
148    #[cfg(feature = "typesize")]
149    type InlineStrRepr: Copy + AsRef<[u8]> + AsMut<[u8]> + Default + typesize::TypeSize;
150    #[cfg(not(feature = "typesize"))]
151    type InlineStrRepr: Copy + AsRef<[u8]> + AsMut<[u8]> + Default;
152
153    #[must_use]
154    fn to_usize(self) -> usize;
155
156    #[must_use]
157    fn from_usize(len: usize) -> Option<Self> {
158        len.try_into().ok()
159    }
160}
161
162impl ValidLength for u8 {
163    const ZERO: Self = 0;
164    const MAX: Self = Self::MAX;
165    #[allow(deprecated)]
166    const DANGLING: Self::NonZero = Self::NonZero::MAX;
167
168    type NonZero = NonZeroU8;
169    type InlineStrRepr = [u8; get_heap_threshold::<Self>()];
170
171    fn to_usize(self) -> usize {
172        self.into()
173    }
174}
175
176impl ValidLength for u16 {
177    const ZERO: Self = 0;
178    const MAX: Self = Self::MAX;
179    #[allow(deprecated)]
180    const DANGLING: Self::NonZero = Self::NonZero::MAX;
181
182    type NonZero = NonZeroU16;
183    type InlineStrRepr = [u8; get_heap_threshold::<Self>()];
184
185    fn to_usize(self) -> usize {
186        self.into()
187    }
188}
189
190#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
191impl ValidLength for u32 {
192    const ZERO: Self = 0;
193    const MAX: Self = Self::MAX;
194    #[allow(deprecated)]
195    const DANGLING: Self::NonZero = Self::NonZero::MAX;
196
197    type NonZero = NonZeroU32;
198    type InlineStrRepr = [u8; get_heap_threshold::<Self>()];
199
200    fn to_usize(self) -> usize {
201        self.try_into()
202            .expect("u32 can fit into usize on platforms with pointer lengths of 32 and 64")
203    }
204}
205
206#[cfg(target_pointer_width = "16")]
207pub type SmallLen = u16;
208#[cfg(not(target_pointer_width = "16"))]
209pub type SmallLen = u32;