small_fixed_array/
length.rs1use 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 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 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
132pub 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;