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}