Skip to main content

fastvec/
utils.rs

1//! Internal helpers shared by vector implementations.
2
3/// Creates an initialized value for a zero-sized type.
4///
5/// # Safety
6///
7/// `T` must be a zero-sized type.
8#[inline(always)]
9pub(super) const unsafe fn zst_init<T>() -> T {
10    debug_assert!(::core::mem::size_of::<T>() == 0);
11
12    #[expect(clippy::uninit_assumed_init)]
13    unsafe {
14        core::mem::MaybeUninit::uninit().assume_init()
15    }
16}
17
18#[cold]
19#[inline(never)]
20pub(super) const fn cold_path() {}
21
22/// Compile-time flag for whether a type is zero-sized.
23pub(super) trait IsZST {
24    const IS_ZST: bool;
25}
26
27impl<T> IsZST for T {
28    /// A flag used to indicate the ZST (zero sized type).
29    ///
30    /// This will be optimized by the compiler and will not take up additional space.
31    ///
32    /// Don't worry about the additional overhead of branching statements.
33    const IS_ZST: bool = ::core::mem::size_of::<T>() == 0;
34}
35
36/// Chooses a minimum non-zero capacity heuristic for type `T`.
37#[inline(always)]
38pub(super) const fn min_cap<T>() -> usize {
39    let size = ::core::mem::size_of::<T>();
40    if size < 1 {
41        8
42    } else if size <= 1024 {
43        4
44    } else {
45        1
46    }
47}
48
49/// Converts generic range bounds into normalized `(start, end)` indices.
50///
51/// # Panics
52///
53/// Panics if `start > end` or `end > len`.
54#[inline(never)]
55pub(super) fn split_range_bound(
56    src: &impl core::ops::RangeBounds<usize>,
57    len: usize,
58) -> (usize, usize) {
59    let start = match src.start_bound() {
60        core::ops::Bound::Included(&i) => i,
61        core::ops::Bound::Excluded(&i) => i + 1,
62        core::ops::Bound::Unbounded => 0,
63    };
64
65    let end = match src.end_bound() {
66        core::ops::Bound::Included(&i) => i + 1,
67        core::ops::Bound::Excluded(&i) => i,
68        core::ops::Bound::Unbounded => len,
69    };
70
71    assert!(start <= end, "drain start greater than end");
72    assert!(end <= len, "drain end out of bounds");
73    (start, end)
74}
75
76macro_rules! impl_common_traits {
77    ($name:ty) => {
78        impl<T, const N: usize> core::ops::Deref for $name {
79            type Target = [T];
80            #[inline]
81            fn deref(&self) -> &Self::Target {
82                self.as_slice()
83            }
84        }
85
86        impl<T, const N: usize> core::ops::DerefMut for $name {
87            #[inline]
88            fn deref_mut(&mut self) -> &mut Self::Target {
89                self.as_mut_slice()
90            }
91        }
92
93        impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for $name {
94            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95                core::fmt::Debug::fmt(self.as_slice(), f)
96            }
97        }
98
99        impl<T, const N: usize> core::convert::AsRef<[T]> for $name {
100            #[inline]
101            fn as_ref(&self) -> &[T] {
102                self.as_slice()
103            }
104        }
105
106        impl<T, const N: usize> core::convert::AsRef<$name> for $name {
107            #[inline]
108            fn as_ref(&self) -> &$name {
109                self
110            }
111        }
112
113        impl<T, const N: usize> core::convert::AsMut<[T]> for $name {
114            #[inline]
115            fn as_mut(&mut self) -> &mut [T] {
116                self.as_mut_slice()
117            }
118        }
119
120        impl<T, const N: usize> core::convert::AsMut<$name> for $name {
121            #[inline]
122            fn as_mut(&mut self) -> &mut $name {
123                self
124            }
125        }
126
127        impl<T, const N: usize> core::borrow::Borrow<[T]> for $name {
128            #[inline]
129            fn borrow(&self) -> &[T] {
130                self.as_slice()
131            }
132        }
133
134        impl<T, const N: usize> core::borrow::BorrowMut<[T]> for $name {
135            #[inline]
136            fn borrow_mut(&mut self) -> &mut [T] {
137                self.as_mut_slice()
138            }
139        }
140
141        impl<T: core::hash::Hash, const N: usize> core::hash::Hash for $name {
142            #[inline]
143            fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
144                core::hash::Hash::hash(self.as_slice(), state);
145            }
146        }
147
148        impl<T, I: core::slice::SliceIndex<[T]>, const N: usize> core::ops::Index<I> for $name {
149            type Output = <I as core::slice::SliceIndex<[T]>>::Output;
150            #[inline]
151            fn index(&self, index: I) -> &Self::Output {
152                core::ops::Index::index(self.as_slice(), index)
153            }
154        }
155
156        impl<T, I: core::slice::SliceIndex<[T]>, const N: usize> core::ops::IndexMut<I> for $name {
157            #[inline]
158            fn index_mut(&mut self, index: I) -> &mut Self::Output {
159                core::ops::IndexMut::index_mut(self.as_mut_slice(), index)
160            }
161        }
162
163        impl<'a, T, const N: usize> IntoIterator for &'a $name {
164            type Item = &'a T;
165            type IntoIter = core::slice::Iter<'a, T>;
166            #[inline]
167            fn into_iter(self) -> Self::IntoIter {
168                self.as_slice().iter()
169            }
170        }
171
172        impl<'a, T, const N: usize> IntoIterator for &'a mut $name {
173            type Item = &'a mut T;
174            type IntoIter = core::slice::IterMut<'a, T>;
175            #[inline]
176            fn into_iter(self) -> Self::IntoIter {
177                self.as_mut_slice().iter_mut()
178            }
179        }
180
181        impl<T: core::cmp::Ord, const N: usize> core::cmp::Ord for $name {
182            #[inline]
183            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
184                core::cmp::Ord::cmp(self.as_slice(), other.as_slice())
185            }
186        }
187
188        impl<T: core::cmp::PartialOrd, const N: usize> core::cmp::PartialOrd for $name {
189            #[inline]
190            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
191                core::cmp::PartialOrd::partial_cmp(self.as_slice(), other.as_slice())
192            }
193        }
194
195        impl<T: Eq, const N: usize> Eq for $name {}
196
197        impl<T, U, const N: usize> core::cmp::PartialEq<[U]> for $name
198        where
199            T: core::cmp::PartialEq<U>,
200        {
201            #[inline]
202            fn eq(&self, other: &[U]) -> bool {
203                core::cmp::PartialEq::eq(self.as_slice(), other)
204            }
205        }
206
207        impl<T, U, const N: usize> core::cmp::PartialEq<&[U]> for $name
208        where
209            T: core::cmp::PartialEq<U>,
210        {
211            #[inline]
212            fn eq(&self, other: &&[U]) -> bool {
213                core::cmp::PartialEq::eq(self.as_slice(), *other)
214            }
215        }
216
217        impl<T, U, const N: usize> core::cmp::PartialEq<&mut [U]> for $name
218        where
219            T: core::cmp::PartialEq<U>,
220        {
221            #[inline]
222            fn eq(&self, other: &&mut [U]) -> bool {
223                core::cmp::PartialEq::eq(self.as_slice(), *other)
224            }
225        }
226
227        impl<T, U, const N: usize, const P: usize> core::cmp::PartialEq<[U; P]> for $name
228        where
229            T: core::cmp::PartialEq<U>,
230        {
231            #[inline]
232            fn eq(&self, other: &[U; P]) -> bool {
233                core::cmp::PartialEq::eq(self.as_slice(), other.as_slice())
234            }
235        }
236
237        impl<T, U, const N: usize, const P: usize> core::cmp::PartialEq<&[U; P]> for $name
238        where
239            T: core::cmp::PartialEq<U>,
240        {
241            #[inline]
242            fn eq(&self, other: &&[U; P]) -> bool {
243                core::cmp::PartialEq::eq(self.as_slice(), other.as_slice())
244            }
245        }
246    };
247}
248
249pub(super) use impl_common_traits;