runtime_sized_array/
array.rs

1use std::alloc::{Layout, LayoutError};
2
3use super::ArrayError;
4use super::{Iter, IterMut, IntoIter};
5
6
7/// Base `struct` of the crate.
8///
9/// A variable-length array - data structure whose length is determined at run time
10/// (instead of at compile time).
11///
12/// # Example
13///
14/// Basic usage:
15///
16/// ```
17/// use runtime_sized_array::Array;
18/// let arr: Array<i32> = Array::new(10).unwrap();
19/// arr[2] == 3;
20/// ```
21///
22pub struct Array<T> {
23    pub(in super) pointer : *mut T,
24    size : usize
25}
26
27impl<T> Array<T> {
28
29    /// Creates an `Array` with the given size or returns `ArrayError`
30    /// if any of the following cases happened:
31    /// * failed creating a [`layout`] with the following size,
32    /// * failed [allocating] memory for the array.
33    ///
34    /// [allocating]: std::alloc
35    /// [`layout`]: std::alloc::Layout
36    #[inline]
37    pub fn new(size: usize) -> Result<Array<T>, ArrayError> {
38        unsafe {
39            let layout = std::alloc::Layout::array::<T>(size)?;
40            let ptr = std::alloc::alloc(layout) as *mut T;
41            if ptr.is_null() {
42                Err(ArrayError("allocation returned null pointer".to_string()))
43            } else {
44                Ok(Self { pointer: ptr, size })
45            }
46        }
47    }
48
49
50    /// Creates an `Array` from the given raw pointer with the given size
51    ///
52    /// # Safety
53    ///
54    /// The caller must ensure that the memory the `ptr` refers can be deallocated
55    /// by another structure. Also dropping the array, returned by this function
56    /// will immediately cause deallocating of the memory. All this may cause undefined
57    /// behaviour.
58    ///
59    /// What's more, the function does not check is the pointer is null.
60    ///
61    ///
62    /// # Example
63    ///
64    /// ```
65    /// use runtime_sized_array::Array;
66    /// let mut vec = vec![1,2,3];
67    /// let ptr = vec.as_mut_ptr();
68    /// let size = vec.len();
69    /// unsafe {
70    ///     let arr: Array<i32> = Array::from_pointer(ptr, size);
71    /// }
72    /// ```
73    #[inline]
74    pub unsafe fn from_pointer(ptr: *mut T, size: usize) -> Self {
75        Self { pointer : ptr, size }
76    }
77
78
79
80    /// size of the array
81    #[inline]
82    pub fn size(&self) -> usize {
83        self.size
84    }
85
86
87    /// Returns an immutable raw pointer at an element by the given index
88    ///
89    /// # Example
90    ///
91    /// ```
92    /// use runtime_sized_array::Array;
93    ///
94    /// let arr: Array<i32> = vec![1,2,4].into();
95    /// unsafe {
96    ///     assert_eq!(*arr.get_ptr(1), 2)
97    /// }
98    ///
99    /// // arr.get_ptr(10) - undefined behaviour
100    /// ```
101    ///
102    /// # Safety
103    ///
104    /// This method does not check the index bounds, so it's more efficient,
105    /// but can produce undefined behaviour
106    ///
107    #[inline]
108    pub unsafe fn get_ptr(&self, index: usize) -> *const T {
109        self.pointer.add(index)
110    }
111
112    /// Returns a mutable raw pointer at an element by the given index
113    ///
114    /// # Example
115    ///
116    /// ```
117    /// use runtime_sized_array::Array;
118    ///
119    /// let arr: Array<i32> = vec![1,2,4].into();
120    /// unsafe {
121    ///     assert_eq!(*arr.get_ptr(1), 2)
122    /// }
123    ///
124    /// // arr.get_ptr(10) - undefined behaviour
125    /// ```
126    ///
127    /// # Safety
128    ///
129    /// This method does not check the index bounds, so it's more efficient,
130    /// but can produce undefined behaviour
131    ///
132    #[inline]
133    pub unsafe fn get_mut_ptr(&self, index: usize) -> *mut T {
134        self.pointer.add(index)
135    }
136
137    /// Returns immutable reference at an element
138    /// or None if the given index is out of bounds.
139    ///
140    /// # Example
141    ///
142    /// ```
143    /// use runtime_sized_array::Array;
144    ///
145    /// let arr: Array<i32> = vec![1,2,4].into();
146    /// assert_eq!(arr.try_get(1), Some(&2));
147    /// assert_eq!(arr.try_get(10), None);
148    /// ```
149    #[inline]
150    pub fn try_get(&self, index: usize) -> Option<&T> {
151        if self.size <= index {
152            None
153        } else {
154            unsafe { Some(self.get(index)) }
155        }
156    }
157
158    /// Returns immutable reference at an element by the given index
159    ///
160    /// # Example
161    ///
162    /// ```
163    /// use runtime_sized_array::Array;
164    ///
165    /// let arr: Array<i32> = vec![1,2,4].into();
166    /// unsafe {
167    ///     assert_eq!(arr.get(1), &2)
168    /// }
169    ///
170    /// // arr.get(10) - undefined behaviour
171    /// ```
172    ///
173    /// # Safety
174    ///
175    /// This method does not check the index bounds, so it's more efficient,
176    /// but can produce undefined behaviour
177    ///
178    /// If you want safe immutable access, use [`try_get`](Array::try_get).
179    #[inline]
180    pub unsafe fn get(&self, index: usize) -> &T {
181        &(*(self.pointer.add(index)))
182    }
183
184    /// Returns mutable reference at an element
185    /// or None if the given index is out of bounds.
186    ///
187    /// # Example
188    ///
189    /// ```
190    /// use runtime_sized_array::Array;
191    ///
192    /// let mut arr: Array<i32> = vec![1,2,4].into();
193    /// *arr.try_get_mut(1).unwrap() = 5;
194    /// assert_eq!(arr.try_get_mut(10), None);
195    /// ```
196    #[inline]
197    pub fn try_get_mut(&mut self, index: usize) -> Option<&mut T> {
198        if self.size <= index {
199            None
200        } else {
201            unsafe { Some(self.get_mut(index)) }
202        }
203    }
204
205    /// Returns mutable reference at an element by the given index
206    ///
207    /// # Example
208    ///
209    /// ```
210    /// use runtime_sized_array::Array;
211    ///
212    /// let mut arr: Array<i32> = vec![1,2,4].into();
213    /// unsafe {
214    ///     *arr.get_mut(1) = 2;
215    /// }
216    ///
217    /// // *arr.get_mut(10) == 4; - undefined behaviour
218    /// ```
219    ///
220    /// # Safety
221    ///
222    /// This method does not check the index bounds, so it's more efficient,
223    /// but can produce undefined behaviour
224    ///
225    /// If you want safe mutable access, use [`try_get_mut`](Array::try_get_mut).
226    #[inline]
227    pub unsafe fn get_mut(&mut self, index: usize) -> &mut T {
228        &mut (*(self.pointer.add(index)))
229    }
230
231    /// Alternative way to safely change elements of the array.
232    ///
233    /// Returns () or None if the given index is out of bounds
234    ///
235    /// # Example
236    ///
237    /// ```
238    /// use runtime_sized_array::Array;
239    ///
240    /// let mut arr: Array<i32> = vec![1,2,4].into();
241    /// assert_eq!(arr.try_set(1, 5), Some(()));
242    /// assert_eq!(arr.try_set(10, 4), None);
243    /// ```
244    #[inline]
245    pub fn try_set(&mut self, index: usize, value: T) -> Option<()> {
246        if self.size <= index {
247            None
248        } else {
249            unsafe { Some(self.set(index, value)) }
250        }
251    }
252
253    /// Alternative way to unsafely change elements of the array.
254    ///
255    /// Returns () or None if the given index is out of bounds
256    ///
257    /// # Example
258    ///
259    /// ```
260    /// use runtime_sized_array::Array;
261    ///
262    /// let mut arr: Array<i32> = vec![1,2,4].into();
263    /// unsafe {
264    ///     arr.set(1, 5);
265    /// }
266    ///
267    /// // arr.set(10, 4); - undefined behaviour
268    /// ```
269    ///
270    /// # Safety
271    ///
272    /// This method does not check the index bounds, so it's more efficient,
273    /// but can produce undefined behaviour
274    ///
275    /// If you look for safe version, use [`try_set`](Array::try_set).
276    #[inline]
277    pub unsafe fn set(&mut self, index: usize, value: T) {
278        *(self.pointer.add(index)) = value
279    }
280
281    /// Returns an iterator over the array.
282    ///
283    /// The iterator yields all items from start to end.
284    ///
285    /// # Examples
286    ///
287    /// ```
288    /// use runtime_sized_array::Array;
289    ///
290    /// let mut arr: Array<i32> = vec![1,2,4].into();
291    /// let mut iterator = arr.iter();
292    ///
293    /// assert_eq!(iterator.next(), Some(&1));
294    /// assert_eq!(iterator.next(), Some(&2));
295    /// assert_eq!(iterator.next(), Some(&4));
296    /// assert_eq!(iterator.next(), None);
297    /// ```
298    #[inline]
299    pub fn iter(&self) -> Iter<T> {
300        Iter::new(self)
301    }
302
303    /// Returns an iterator that allows modifying each value.
304    ///
305    /// The iterator yields all items from start to end.
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use runtime_sized_array::Array;
311    ///
312    /// let mut arr: Array<i32> = vec![1,2,4].into();
313    /// for elem in arr.iter_mut() {
314    ///     *elem += 2;
315    /// }
316    /// assert_eq!(arr[0], 3);
317    /// ```
318    #[inline]
319    pub fn iter_mut(&mut self) -> IterMut<T> {
320        IterMut::new(self)
321    }
322
323    /// Converts the array into a [`Vec`](std::vec::Vec)
324    ///
325    /// The array cannot be used after calling this.
326    #[inline]
327    pub fn into_vec(self) -> Vec<T> {
328        unsafe{
329            Vec::from_raw_parts(self.pointer, self.size, self.size)
330        }
331    }
332
333    /// Returns immutable raw pointer to the memory, allocated by the array.
334    ///
335    /// The caller must ensure that the array outlives the pointer this
336    /// function returns, or else it will end up pointing to garbage.
337    ///
338    /// The caller must also ensure that the memory the pointer (non-transitively) points to
339    /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
340    /// derived from it. If you need to mutate the contents of the array, use [`as_mut_ptr`].
341    ///
342    /// # Examples
343    ///
344    /// ```
345    /// use runtime_sized_array::Array;
346    ///
347    /// let mut arr: Array<i32> = vec![1,2,4].into();
348    /// let ptr = arr.as_ptr();
349    /// unsafe {
350    ///     for i in 0..arr.size() {
351    ///         assert_eq!(arr[i], *ptr.add(i));
352    ///     }
353    /// }
354    /// ```
355    ///
356    /// [`as_mut_ptr`]: Array::as_mut_ptr
357    #[inline]
358    pub fn as_ptr(&self) -> *const T {
359        self.pointer.as_const()
360    }
361
362    /// Returns mutable raw pointer to the memory, allocated by the array.
363    ///
364    /// The caller must ensure that the array outlives the pointer this
365    /// function returns, or else it will end up pointing to garbage.
366    ///
367    /// # Examples
368    ///
369    /// ```
370    /// use runtime_sized_array::Array;
371    ///
372    /// let mut arr: Array<i32> = vec![1,2,4].into();
373    /// let ptr = arr.as_mut_ptr();
374    /// unsafe {
375    ///     for i in 0..arr.size() {
376    ///         *ptr.add(i) += 2;
377    ///     }
378    /// }
379    /// ```
380    ///
381    #[inline]
382    pub fn as_mut_ptr(&self) -> *mut T {
383        self.pointer
384    }
385
386}
387
388
389impl<'a, T> IntoIterator for &'a Array<T> {
390    type Item = &'a T;
391    type IntoIter = Iter<'a, T>;
392
393    /// Returns an iterator over the array.
394    ///
395    /// The iterator yields all items from start to end.
396    ///
397    /// # Examples
398    ///
399    /// ```
400    /// use runtime_sized_array::Array;
401    ///
402    /// let mut arr: Array<i32> = vec![1,2,4].into();
403    /// for item in &arr {
404    ///     println!("{item}");
405    /// }
406    /// ```
407    #[inline]
408    fn into_iter(self) -> Self::IntoIter {
409        self.iter()
410    }
411}
412
413
414impl<'a, T> IntoIterator for &'a mut Array<T> {
415    type Item = &'a mut T;
416    type IntoIter = IterMut<'a, T>;
417
418    /// Returns an iterator that allows modifying each value.
419    ///
420    /// The iterator yields all items from start to end.
421    ///
422    /// # Examples
423    ///
424    /// ```
425    /// use runtime_sized_array::Array;
426    ///
427    /// let mut arr: Array<i32> = vec![1,2,4].into();
428    /// for elem in &mut arr {
429    ///     *elem += 2;
430    /// }
431    /// assert_eq!(arr[0], 3);
432    /// ```
433    #[inline]
434    fn into_iter(self) -> Self::IntoIter {
435        self.iter_mut()
436    }
437}
438
439
440impl<T> IntoIterator for Array<T> {
441    type Item = T;
442    type IntoIter = IntoIter<T>;
443
444    /// Creates a consuming iterator, that is, one that moves each value out of
445    /// the array (from start to end).
446    ///
447    /// The array cannot be used after calling this.
448    #[inline]
449    fn into_iter(self) -> Self::IntoIter {
450        IntoIter::new(self)
451    }
452}
453
454
455impl<T> std::ops::Index<usize> for Array<T> {
456    type Output = T;
457
458    #[inline]
459    #[rustc_on_unimplemented(
460        message = "array indices are of type `usize` or `Index`",
461        label = "array indices are of type `usize` or `Index`"
462    )]
463    fn index(&self, index: usize) -> &Self::Output {
464        self.try_get(index).expect("index out of bounds")
465    }
466}
467
468
469impl<T> std::ops::IndexMut<usize> for Array<T> {
470
471    #[inline]
472    #[rustc_on_unimplemented(
473        message = "array indices are of type `usize` or `Index`",
474        label = "array indices are of type `usize` or `Index`"
475    )]
476    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
477        self.try_get_mut(index).expect("index out of bounds")
478    }
479}
480
481
482impl<T> Drop for Array<T> {
483
484    fn drop(&mut self) {
485        unsafe { self.pointer.drop_in_place() };
486    }
487}
488
489
490impl<T> From<Vec<T>> for Array<T> {
491
492    /// Converts a `Vec<T>` to `Array<T>`.
493    ///
494    /// # Panics
495    ///
496    /// if any of the following cases happened:
497    /// * failed creating a [`layout`] with the following size,
498    /// * failed allocating memory for the array.
499    ///
500    /// # Example
501    ///
502    /// ```
503    /// use runtime_sized_array::Array;
504    /// let source: Vec<i32> = vec![0, 1, 2, 3];
505    /// let arr : Array<i32> = source.into();
506    ///
507    /// for i in 0..4 {
508    ///     assert_eq!(arr[i], i as i32)
509    /// }
510    /// ```
511    ///
512    /// [allocating]: std::alloc
513    /// [`layout`]: std::alloc::Layout
514    fn from(vec: Vec<T>) -> Self {
515        let size = vec.len();
516        let mut array = Array::new(size)
517            .expect("failed to create new Array");
518        let mut i = 0_usize;
519        unsafe {
520            for item in vec {
521                *array.get_mut(i) = item;
522                i += 1
523            }
524        }
525        array
526    }
527}
528
529
530impl<T: Clone> Clone for Array<T> {
531
532    /// Copies all elements of one array to another.
533    ///
534    /// # Note
535    ///
536    /// The elements are copied by value, not by reference.
537    /// So changing elements of the new array will not cause
538    /// changing elements of the old one.
539    ///
540    /// # Advanced
541    ///
542    /// That's because multi-handling one pointer will lead to
543    /// undefined behaviour, when one of them is dropped and deallocates
544    /// the memory of it's pointer
545    /// and another one is still trying to use the same pointer.
546    ///
547    /// # Panics
548    ///
549    /// if any of the following cases happened:
550    /// * failed creating a [`layout`] with the following size,
551    /// * failed allocating memory for the array.
552    ///
553    /// # Example
554    ///
555    /// ```
556    /// use runtime_sized_array::Array;
557    /// let old_arr: Array<i32> = vec![5, 1, 0, 3].into();
558    /// let new_arr : Array<i32> = old_arr.clone();
559    ///
560    /// for i in 0..4 {
561    ///     assert_eq!(old_arr[i], new_arr[i]);
562    /// }
563    /// ```
564    ///
565    /// [allocating]: std::alloc
566    /// [`layout`]: std::alloc::Layout
567    fn clone(&self) -> Self {
568        let arr = Array::new(self.size)
569            .expect("failed to crate new Array");
570        unsafe {
571            for i in 0..self.size {
572                *arr.get_mut_ptr(i) = std::ptr::read(self.get_ptr(i));
573            }
574        }
575        arr
576    }
577}
578
579
580impl<T> std::ops::Deref for Array<T> {
581    type Target = [T];
582
583    #[inline]
584    fn deref(&self) -> &Self::Target {
585        unsafe { std::slice::from_raw_parts(self.pointer, self.size) }
586    }
587}
588
589
590impl<T> std::ops::DerefMut for Array<T> {
591
592    #[inline]
593    fn deref_mut(&mut self) -> &mut Self::Target {
594        unsafe { std::slice::from_raw_parts_mut(self.pointer, self.size) }
595    }
596}
597
598
599// additional functionality
600impl<T> Array<T> {
601
602    /// Tries to take `n` items from the given `iterator` and
603    /// to put them into array of size `n`
604    ///
605    /// If the `iterator` ends, before the array is filled, then
606    /// some elements will be uninitialized
607    ///
608    /// # Panics
609    ///
610    /// if any of the following cases happened:
611    /// * failed creating a [`layout`] with the following size,
612    /// * failed allocating memory for the array.
613    ///
614    /// # Example
615    ///
616    /// ```
617    /// use runtime_sized_array::Array;
618    /// let mut iter = vec![0,1,2,3,4,5].into_iter();
619    /// let arr : Array<i32> = Array::take_from_iter(&mut iter, 3);
620    ///
621    /// for i in 0..3 {
622    ///     assert_eq!(arr[i], i as i32)
623    /// }
624    /// ```
625    ///
626    ///
627    /// [allocating]: std::alloc
628    /// [`layout`]: std::alloc::Layout
629    pub fn take_from_iter<I: Iterator>(iterator: &mut I, n: usize) -> Self
630        where
631            I : Iterator,
632            T : From<I::Item>
633    {
634        let mut arr = Array::new(n)
635            .expect("failed to create new Array");
636        unsafe {
637            for i in 0..n {
638                match iterator.next() {
639                    None => break,
640                    Some(val) => *arr.get_mut_ptr(i) = val.into()
641                }
642            }
643        }
644        arr
645    }
646}