Skip to main content

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