dynamic_array/
array.rs

1use std::{
2    alloc::{alloc_zeroed, Layout},
3    cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
4    convert::{TryFrom, TryInto},
5    fmt,
6    fmt::{Debug, Formatter},
7    ops::{Deref, DerefMut, Index, IndexMut},
8    ptr::NonNull,
9    slice::SliceIndex,
10};
11
12/// A dynamically-allocated array of fixed size.
13///
14/// # Example
15///
16/// ```
17/// use dynamic_array::SmallArray;
18///
19/// let mut arr = SmallArray::<u32>::zeroed(9);
20///
21/// assert!(!arr.is_empty());
22///
23/// // can be freely dereferenced
24/// assert_eq!(arr[3], 0);
25///
26/// arr[7] = 8;
27///
28/// assert_eq!(arr[7], 8);
29///
30/// let mut arr2 = arr.clone();
31///
32/// assert_ne!(arr2[3], 4);
33/// arr[2] = 4;
34/// arr[4] = 0xdead;
35/// arr2[3] = 4;
36/// assert_eq!(arr[2], 4);
37///
38/// // can be sliced
39/// assert_eq!(arr[2..5], [4u32, 0, 0xdead]);
40///
41/// // can also be freely iterated
42/// for x in arr.iter_mut() {
43///     *x += 1;
44/// }
45///
46/// assert_eq!(arr[2], 5);
47///
48/// ```
49#[cfg_attr(feature = "packed", repr(packed))]
50pub struct Array<T, Len: Copy + Into<usize> + TryFrom<usize>> {
51    ptr: NonNull<T>,
52    len: Len,
53}
54
55unsafe impl<T: Sync, Len: Copy + Into<usize> + TryFrom<usize>> Sync for Array<T, Len> {}
56unsafe impl<T: Send, Len: Copy + Into<usize> + TryFrom<usize>> Send for Array<T, Len> {}
57
58impl<T, Len: Copy + Into<usize> + TryFrom<usize>> Drop for Array<T, Len> {
59    fn drop(&mut self) {
60        unsafe {
61            std::ptr::drop_in_place(self.deref_mut());
62            Vec::from_raw_parts(self.ptr.as_ptr(), 0, self.len.into());
63        }
64    }
65}
66
67impl<T, Len: Copy + Into<usize> + TryFrom<usize>> Array<T, Len> {
68    /// Creates a zeroed `Array` with length `len`.
69    pub fn zeroed(len: Len) -> Self {
70        unsafe {
71            let len_u = len.into();
72            let layout = Layout::array::<T>(len_u).unwrap();
73
74            let ptr = if len_u != 0 {
75                alloc_zeroed(layout).cast::<T>()
76            } else {
77                // SAFETY: the pointer doesn't matter if the length is 0
78                0xdead as *mut T
79            };
80
81            Self::from_raw(ptr, len)
82        }
83    }
84
85    /// Constructs a new `Array` from a raw pointer.
86    ///
87    /// After calling this function the pointer is owned by the resulting `Array`.
88    pub fn from_raw(raw: *mut T, len: Len) -> Self {
89        Self {
90            ptr: NonNull::new(raw).unwrap(),
91            len,
92        }
93    }
94
95    /// Extracts a slice containing all the elements of `self`.
96    pub fn as_slice(&self) -> &[T] {
97        self
98    }
99
100    /// Extracts a mutable slice containing all the elements of `self`.
101    pub fn as_slice_mut(&mut self) -> &mut [T] {
102        self
103    }
104
105    /// Constructs a new `Array` from a given `Vec`.
106    ///
107    /// # Example
108    ///
109    /// ```
110    /// use dynamic_array::SmallArray;
111    ///
112    /// let mut v = vec![8,9,10usize];
113    /// v.reserve(1000);
114    ///
115    /// let arr = SmallArray::from_vec(v);
116    ///
117    /// assert_eq!(arr.len(), 3);
118    /// ```
119    pub fn from_vec(mut v: Vec<T>) -> Self
120    where
121        <Len as TryFrom<usize>>::Error: Debug,
122    {
123        let len = v.len().try_into().unwrap();
124        let ptr = v.as_mut_ptr();
125        std::mem::forget(v);
126
127        Self::from_raw(ptr, len)
128    }
129
130    /// Constructs a `Vec` from `Self`.
131    ///
132    /// # Example
133    ///
134    /// ```
135    /// use dynamic_array::SmallArray;
136    ///
137    /// let arr = SmallArray::<usize>::zeroed(5);
138    ///
139    /// let v: Vec<usize> = arr.into_vec();
140    ///
141    /// assert_eq!(v.len(), 5);
142    /// assert_eq!(v[3], 0);
143    /// ```
144    pub fn into_vec(self) -> Vec<T> {
145        unsafe {
146            let size = self.len().try_into().unwrap();
147            let v = Vec::from_raw_parts(self.ptr.as_ptr(), size, size);
148            std::mem::forget(self);
149            v
150        }
151    }
152
153    /// The length of the array
154    ///
155    /// # Example
156    ///
157    /// ```
158    /// use dynamic_array::SmallArray;
159    /// let arr = SmallArray::<()>::zeroed(42);
160    ///
161    /// assert_eq!(arr.len(), 42);
162    /// ```
163    pub fn len(&self) -> Len {
164        self.len
165    }
166
167    pub fn is_empty(&self) -> bool {
168        self.len().into() == 0
169    }
170}
171
172/**********************************************************************/
173// Trait implementations
174
175impl<T: Clone, Len: Copy + Into<usize> + TryFrom<usize>> Clone for Array<T, Len> {
176    fn clone(&self) -> Self {
177        unsafe {
178            let other = Self::zeroed(self.len);
179
180            // If len == 0 this shouldn't cost anything
181            other
182                .ptr
183                .as_ptr()
184                .copy_from_nonoverlapping(self.ptr.as_ptr(), self.len.into());
185
186            other
187        }
188    }
189}
190
191impl<T, Len: Copy + Into<usize> + TryFrom<usize>> Deref for Array<T, Len> {
192    type Target = [T];
193
194    fn deref(&self) -> &[T] {
195        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len.into()) }
196    }
197}
198
199impl<T, Len: Copy + Into<usize> + TryFrom<usize>> DerefMut for Array<T, Len> {
200    fn deref_mut(&mut self) -> &mut [T] {
201        unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len.into()) }
202    }
203}
204
205impl<T: Debug, Len: Copy + Into<usize> + TryFrom<usize>> Debug for Array<T, Len> {
206    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
207        fmt::Debug::fmt(self.as_slice(), f)
208    }
209}
210
211impl<T, Len: Copy + Into<usize> + TryFrom<usize>> IntoIterator for Array<T, Len> {
212    type Item = T;
213    type IntoIter = std::vec::IntoIter<T>;
214
215    fn into_iter(self) -> Self::IntoIter {
216        self.into_vec().into_iter()
217    }
218}
219
220impl<'t, T, Len: Copy + Into<usize> + TryFrom<usize>> IntoIterator for &'t Array<T, Len> {
221    type Item = &'t T;
222    type IntoIter = std::slice::Iter<'t, T>;
223
224    fn into_iter(self) -> std::slice::Iter<'t, T> {
225        self.iter()
226    }
227}
228
229impl<'t, T, Len: Copy + Into<usize> + TryFrom<usize>> IntoIterator for &'t mut Array<T, Len> {
230    type Item = &'t mut T;
231    type IntoIter = std::slice::IterMut<'t, T>;
232
233    fn into_iter(self) -> std::slice::IterMut<'t, T> {
234        self.iter_mut()
235    }
236}
237
238impl<T, Len> Eq for Array<T, Len>
239where
240    T: Eq,
241    Len: Copy + Into<usize> + TryFrom<usize>,
242{
243}
244
245impl<T, Len> PartialEq for Array<T, Len>
246where
247    T: PartialEq<T>,
248    Len: Copy + Into<usize> + TryFrom<usize>,
249{
250    #[inline]
251    fn eq(&self, other: &Self) -> bool {
252        self[..] == other[..]
253    }
254    #[inline]
255    fn ne(&self, other: &Self) -> bool {
256        self[..] != other[..]
257    }
258}
259
260impl<T, Len, U> PartialEq<[U]> for Array<T, Len>
261where
262    T: PartialEq<U>,
263    Len: Copy + Into<usize> + TryFrom<usize>,
264{
265    #[inline]
266    fn eq(&self, other: &[U]) -> bool {
267        self[..] == other[..]
268    }
269    #[inline]
270    fn ne(&self, other: &[U]) -> bool {
271        self[..] != other[..]
272    }
273}
274
275impl<T, Len, U, const N: usize> PartialEq<[U; N]> for Array<T, Len>
276where
277    T: PartialEq<U>,
278    Len: Copy + Into<usize> + TryFrom<usize>,
279{
280    #[inline]
281    fn eq(&self, other: &[U; N]) -> bool {
282        self[..] == other[..]
283    }
284    #[inline]
285    fn ne(&self, other: &[U; N]) -> bool {
286        self[..] != other[..]
287    }
288}
289
290impl<T, Len> Ord for Array<T, Len>
291where
292    T: Ord,
293    Len: Copy + Into<usize> + TryFrom<usize>,
294{
295    #[inline]
296    fn cmp(&self, other: &Self) -> Ordering {
297        Ord::cmp(&**self, &**other)
298    }
299}
300
301impl<T, Len> PartialOrd for Array<T, Len>
302where
303    T: Ord,
304    Len: Copy + Into<usize> + TryFrom<usize>,
305{
306    #[inline]
307    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
308        PartialOrd::partial_cmp(&**self, &**other)
309    }
310}
311
312impl<T, Len, I> Index<I> for Array<T, Len>
313where
314    Len: Copy + Into<usize> + TryFrom<usize>,
315    I: SliceIndex<[T]>,
316{
317    type Output = I::Output;
318
319    #[inline]
320    fn index(&self, index: I) -> &Self::Output {
321        Index::index(&**self, index)
322    }
323}
324
325impl<T, Len, I> IndexMut<I> for Array<T, Len>
326where
327    Len: Copy + Into<usize> + TryFrom<usize>,
328    I: SliceIndex<[T]>,
329{
330    fn index_mut(&mut self, index: I) -> &mut Self::Output {
331        IndexMut::index_mut(&mut **self, index)
332    }
333}
334
335/// `Default` does not always make sense for `Array`. This is an opt-in feature in case it is needed.
336///
337/// The resulting `Array` is rather unusable, as its length is 0.
338#[cfg(feature = "default-derive")]
339impl<T: Default, Len: Copy + Into<usize> + TryFrom<usize>> Default for Array<T, Len>
340where
341    <Len as TryFrom<usize>>::Error: Debug,
342{
343    fn default() -> Self {
344        Self {
345            ptr: NonNull::dangling(),
346            len: 0.try_into().unwrap(),
347        }
348    }
349}
350
351#[cfg(test)]
352mod tests {
353    use super::Array;
354
355    #[cfg(feature = "packed")]
356    #[test]
357    fn packed() {
358        assert_eq!(std::mem::size_of::<Array<usize, u8>>(), 9);
359    }
360
361    #[cfg(not(feature = "packed"))]
362    #[test]
363    fn not_packed() {
364        assert_eq!(std::mem::size_of::<Array<usize, u8>>(), 16);
365    }
366
367    #[cfg(feature = "default-derive")]
368    #[test]
369    fn default() {
370        let arr = Array::<u8, u8>::default();
371        assert_eq!(arr.len(), 0);
372    }
373}