nyarray/array.rs
1//! stack-allocated array structure.
2//! similar to `Vec` in functionality, except [`Array`] lives on the 'stack',
3//! lending it well for scratch arrays.
4//!
5//! this structure is basically a lightweight wrapper over a simple `[T; N]` array type.
6//!
7//! ## examples
8//!
9//! ```
10//! # use nyarray::array::Array;
11//! let mut array = Array::<16, _>::new(); // new array with capacity of 16
12//!
13//! // `Array` functions very similarly to `Vec`.
14//!
15//! array.push(1);
16//! array.push(2);
17//!
18//! assert_eq!(array.len(), 2);
19//! assert_eq!(array[0], 1);
20//!
21//! assert_eq!(array.pop(), Some(2));
22//! assert_eq!(array.len(), 1);
23//!
24//! array[0] = 7;
25//! assert_eq!(array[0], 7);
26//!
27//! array.extend([1, 2, 3]);
28//!
29//! for x in &array {
30//! println!("{x}");
31//! }
32//!
33//! assert_eq!(array, [7, 1, 2, 3]);
34//! ```
35//!
36//! note that, while the terminology "stack-allocated" is used here, one can
37//! easily allocate this structure onto the heap like so:
38//!
39//! ```
40//! # use nyarray::array::Array;
41//! # use std::boxed::Box;
42//! let array = Box::new(Array::<16, ()>::new());
43//! ```
44//!
45//! of course, at this point, one should consider using `Vec` or similar.
46
47use core::mem::ManuallyDrop;
48
49/// stack-allocated array. see [module level documentation](self) for more.
50pub struct Array<const N: usize, T> {
51 buf: [core::mem::MaybeUninit<T>; N],
52 len: usize,
53}
54
55impl<const N: usize, T> Array<N, T> {
56 /// create a new [`Array`].
57 ///
58 /// ## examples
59 ///
60 /// ```
61 /// # use nyarray::array::Array;
62 /// let array = Array::<16, ()>::new(); // array with capacity of 16
63 /// ```
64 #[inline]
65 pub const fn new() -> Self {
66 Self {
67 buf: [const { core::mem::MaybeUninit::uninit() }; N],
68 len: 0,
69 }
70 }
71
72 /// construct an array from a possibly uninitialized array.
73 ///
74 /// ## safety
75 ///
76 /// `buf[0..len]` must be fully initialized memory.
77 ///
78 /// ## examples
79 ///
80 /// this can be useful in combination with [`Self::into_parts_len()`] to
81 /// reconstruct the array after taking it apart for whatever reason.
82 ///
83 /// ```
84 /// # use nyarray::array;
85 /// # use nyarray::array::Array;
86 /// let array = array![1, 2, 3 => 3];
87 ///
88 /// let (buf, len) = array.into_parts_len();
89 ///
90 /// // do whatever to `buf`
91 ///
92 /// let array = unsafe { Array::from_parts_len(buf, len) };
93 /// ```
94 #[inline]
95 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
96 pub const unsafe fn from_parts_len(buf: [core::mem::MaybeUninit<T>; N], len: usize) -> Self {
97 assert!(len <= N);
98
99 Self {
100 buf,
101 len,
102 }
103 }
104
105 /// construct an array from an initialized array.
106 ///
107 /// ## examples
108 ///
109 /// ```
110 /// # use nyarray::array::Array;
111 /// let array = Array::<16, i32>::from_parts([1, 2, 3, 4]);
112 /// assert_eq!(array, [1, 2, 3, 4]);
113 /// ```
114 ///
115 /// ## panics
116 ///
117 /// this method panics if the const parameter `M` is larger than the
118 /// array capacity (const parameter `N`).
119 ///
120 /// ```should_panic
121 /// # use nyarray::array::Array;
122 /// // note the input array is larger than the array capacity
123 /// let array = Array::<4, i32>::from_parts([1, 2, 3, 4, 5, 6]);
124 /// // this panics!
125 /// ```
126 #[inline]
127 pub const fn from_parts<const M: usize>(buf: [T; M]) -> Self {
128 assert!(M <= N);
129
130 let buf = core::mem::ManuallyDrop::new(buf);
131
132 let mut new_buf = [const { core::mem::MaybeUninit::uninit() }; N];
133
134 let buf_ptr = &buf as *const ManuallyDrop<[T; M]> as *const T;
135 let new_ptr = new_buf.as_mut_ptr();
136
137 unsafe {
138 core::ptr::copy_nonoverlapping(buf_ptr, new_ptr as *mut T, M);
139
140 Self::from_parts_len(new_buf, M)
141 }
142 }
143
144 /// construct an array from a raw pointer.
145 ///
146 /// ## safety
147 ///
148 /// - `ptr` must point to memory valid for reads of `len` elements.
149 /// - `ptr` must be aligned.
150 ///
151 /// ## examples
152 ///
153 /// ```
154 /// # use nyarray::array::Array;
155 /// # use std::vec;
156 /// let mut vec = vec![1, 2, 3];
157 /// let array;
158 ///
159 /// unsafe {
160 /// let ptr = vec.as_ptr();
161 /// let len = vec.len();
162 /// vec.set_len(0);
163 /// array = Array::<4, _>::from_raw_parts(ptr, len);
164 /// }
165 ///
166 /// assert_eq!(array, [1, 2, 3]);
167 /// ```
168 #[inline]
169 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
170 pub const unsafe fn from_raw_parts(ptr: *const T, len: usize) -> Self {
171 let mut new_buf = [const { core::mem::MaybeUninit::uninit() }; N];
172
173 let new_ptr = new_buf.as_mut_ptr();
174
175 unsafe {
176 core::ptr::copy_nonoverlapping(ptr, new_ptr as *mut T, len);
177
178 Self::from_parts_len(new_buf, len)
179 }
180 }
181
182 /// deconstruct an array.
183 ///
184 /// note that, let `ret` be the output, `ret.0[0..ret.1]` is valid memory. if
185 /// `T` is `Drop`, then forgetting to drop this will leak memory.
186 ///
187 /// the easiest way to correctly drop this is to reconstruct the array with [`Self::from_parts_len()`].
188 ///
189 /// ## examples
190 ///
191 /// ```
192 /// # use nyarray::array;
193 /// # use nyarray::array::Array;
194 /// let array = array![1, 2, 3 => 3];
195 ///
196 /// let (buf, len) = array.into_parts_len();
197 ///
198 /// // do whatever to `buf`
199 ///
200 /// let array = unsafe { Array::from_parts_len(buf, len) };
201 /// ```
202 #[inline]
203 pub const fn into_parts_len(self) -> ([core::mem::MaybeUninit<T>; N], usize) {
204 let this = core::mem::ManuallyDrop::new(self);
205 let this_ptr = &this as *const core::mem::ManuallyDrop<Self> as *const Self;
206 let buf;
207 let len;
208 unsafe {
209 buf = core::ptr::read(&(*this_ptr).buf);
210 len = (*this_ptr).len;
211 };
212 (buf, len)
213 }
214
215 /// returns the total number of elements the array can hold.
216 /// this function always returns the const `N` parameter of this array.
217 ///
218 /// ## examples
219 ///
220 /// ```
221 /// # use nyarray::array;
222 /// let array = array![1, 2, 3 => 16];
223 /// assert_eq!(array.capacity(), 16);
224 /// ```
225 #[inline]
226 pub const fn capacity(&self) -> usize {
227 N
228 }
229
230 /// returns the total number of elements inside the array.
231 ///
232 /// ## examples
233 ///
234 /// ```
235 /// # use nyarray::array;
236 /// let array = array![1, 2, 3 => 16];
237 /// assert_eq!(array.len(), 3);
238 /// ```
239 #[inline]
240 pub const fn len(&self) -> usize {
241 self.len
242 }
243
244 /// set the length of the array to `new_len`.
245 ///
246 /// ## safety
247 ///
248 /// this function should be used with care, as setting `new_len` to incorrect values
249 /// can easily expose safe code to uninitialized memory.
250 ///
251 /// - `new_len` lesser or equal to [`Self::capacity()`]
252 /// - all elements `0..new_len` must be initialized.
253 ///
254 /// consider using other safe functions, like [`Self::clear()`] or [`Self::extend()`].
255 ///
256 /// ## examples
257 ///
258 /// ```
259 /// # use nyarray::array;
260 /// # use nyarray::array::Array;
261 /// unsafe fn fill(input_ptr: *const u32, input_len: usize) -> Array<16, u32> {
262 /// // it is UB to copy more than the Array capacity (16)
263 /// assert!(input_len <= 16);
264 /// let mut array = array![];
265 /// let array_ptr = array.as_mut_ptr();
266 /// unsafe {
267 /// core::ptr::copy(input_ptr, array_ptr, input_len);
268 /// // set_len *after* copying input
269 /// array.set_len(input_len);
270 /// }
271 /// array
272 /// }
273 /// ```
274 #[inline]
275 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
276 pub const unsafe fn set_len(&mut self, new_len: usize) {
277 self.len = new_len;
278 }
279
280 /// returns `true` if the array has zero elements, `false` otherwise.
281 ///
282 /// ## examples
283 ///
284 /// ```
285 /// # use nyarray::array;
286 /// # use nyarray::array::Array;
287 /// let array: Array<_, ()> = array![=> 4];
288 /// assert!(array.is_empty());
289 /// ```
290 #[inline]
291 pub const fn is_empty(&self) -> bool {
292 self.len() == 0
293 }
294
295 /// returns a slice containing the array.
296 ///
297 /// ## examples
298 ///
299 /// ```
300 /// # use nyarray::array;
301 /// # use nyarray::array::Array;
302 /// let array: Array<_, u8> = array![=> 4];
303 /// let slice: &[u8] = array.as_slice();
304 /// // let slice: &[u8] = &array[..]; // works the same
305 ///
306 /// let string = str::from_utf8(slice);
307 /// ```
308 #[inline]
309 pub const fn as_slice(&self) -> &[T] {
310 let ptr = &self.buf as *const core::mem::MaybeUninit<T> as *const T;
311 unsafe {
312 // safety: all elements before `len` should always be initialized
313 core::slice::from_raw_parts(ptr, self.len)
314 }
315 }
316
317 /// returns a mutable slice containing the array.
318 ///
319 /// ## examples
320 ///
321 /// ```
322 /// # use nyarray::array;
323 /// # use nyarray::array::Array;
324 /// let mut array: Array<_, u8> = array![=> 4];
325 /// let mut slice: &mut [u8] = array.as_mut_slice();
326 /// // let mut slice: &mut [u8] = &mut array[..]; // works the same
327 ///
328 /// let string = str::from_utf8_mut(slice);
329 /// ```
330 #[inline]
331 pub const fn as_mut_slice(&mut self) -> &mut [T] {
332 let ptr = &mut self.buf as *mut core::mem::MaybeUninit<T> as *mut T;
333 unsafe {
334 // safety: all elements before `len` should always be initialized
335 core::slice::from_raw_parts_mut(ptr, self.len)
336 }
337 }
338
339 /// returns a raw pointer to the internal buffer.
340 ///
341 /// this pointer is valid so long as this array is valid. if the array is
342 /// dropped, or even moved, the pointer is immediately invalid.
343 #[inline]
344 pub const fn as_ptr(&self) -> *const T {
345 self.buf.as_ptr() as *const T
346 }
347
348 /// returns a mutable raw pointer to the internal buffer.
349 ///
350 /// this pointer is valid so long as this array is valid. if the array is
351 /// dropped, or even moved, the pointer is immediately invalid.
352 #[inline]
353 pub const fn as_mut_ptr(&mut self) -> *mut T {
354 self.buf.as_mut_ptr() as *mut T
355 }
356
357 /// removes all elements from the array.
358 ///
359 /// ## examples
360 ///
361 /// ```
362 /// # use nyarray::array;
363 /// let mut array = array![1, 2, 3 => 4];
364 /// array.clear();
365 /// assert!(array.is_empty());
366 /// ```
367 #[inline]
368 pub fn clear(&mut self) {
369 unsafe {
370 let elements = self.as_mut_slice() as *mut [T];
371 core::ptr::drop_in_place(elements);
372 self.set_len(0);
373 }
374 }
375
376 /// add an element to the end of the array.
377 ///
378 /// ## examples
379 ///
380 /// ```
381 /// # use nyarray::array;
382 /// let mut array = array![=> 4];
383 /// array.push(1);
384 /// array.push(2);
385 /// array.push(3);
386 /// assert_eq!(array, [1, 2, 3]);
387 /// ```
388 ///
389 /// ## panics
390 ///
391 /// this method panics if there isn't enough space for another element.
392 /// for a non-panicking version, see [`Self::push_checked()`].
393 ///
394 /// ```should_panic
395 /// # use nyarray::array;
396 /// let mut array = array![=> 4];
397 /// array.push(1);
398 /// array.push(2);
399 /// array.push(3);
400 /// array.push(4);
401 /// array.push(5); // panics
402 /// ```
403 #[inline]
404 pub fn push(&mut self, value: T) {
405 if self.push_checked(value).is_err() {
406 panic!("push exceeds capacity");
407 }
408 }
409
410 /// add an element to the end of the array. returns `Err(T)` if
411 /// there is not enough capacity.
412 ///
413 /// ## examples
414 ///
415 /// ```
416 /// # fn main() -> Result<(), i32> {
417 /// # use nyarray::array;
418 /// let mut array = array![=> 4];
419 /// array.push_checked(1)?;
420 /// array.push_checked(2)?;
421 /// array.push_checked(3)?;
422 /// assert_eq!(array, [1, 2, 3]);
423 /// # Ok(())
424 /// # }
425 /// ```
426 #[inline]
427 pub const fn push_checked(&mut self, value: T) -> Result<(), T> {
428 if self.len() == self.capacity() {
429 Err(value)
430 } else {
431 unsafe {
432 // safety: just confirmed there is enough space for another element
433 self.push_unchecked(value);
434 }
435 Ok(())
436 }
437 }
438
439 /// add an element to the end of the array.
440 ///
441 /// this is the unsafe version of this method. see [`Self::push()`] or
442 /// [`Self::push_checked()`] for safe versions of this.
443 ///
444 /// ## safety
445 ///
446 /// there must be enough capacity in the array for at least one more element
447 /// before calling this method. ie; [`Self::len()`] `<` [`Self::capacity()`].
448 ///
449 /// ## examples
450 ///
451 /// ```
452 /// # fn main() -> Result<(), i32> {
453 /// # use nyarray::array;
454 /// let mut array = array![=> 4];
455 /// unsafe {
456 /// // safety: array has capacity of 4 elements.
457 /// array.push_unchecked(1);
458 /// array.push_unchecked(2);
459 /// array.push_unchecked(3);
460 /// array.push_unchecked(4);
461 /// // array.push_unchecked(5); // UB
462 /// }
463 /// assert_eq!(array, [1, 2, 3, 4]);
464 /// # Ok(())
465 /// # }
466 /// ```
467 #[inline]
468 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
469 pub const unsafe fn push_unchecked(&mut self, value: T) {
470 unsafe {
471 let len = self.len();
472
473 // safety: caller ensures there is enough space for another element
474 let ptr = self.as_mut_ptr().add(len);
475
476 core::ptr::write(ptr, value);
477
478 // set length to accomodate for new element
479 self.set_len(len + 1);
480 }
481 }
482
483 /// remove and return an element from the end of the array.
484 /// returns `None` if the array is empty.
485 ///
486 /// ## examples
487 ///
488 /// ```
489 /// # use nyarray::array;
490 /// let mut array = array![1, 2, 3 => 4];
491 /// assert_eq!(array.pop(), Some(3));
492 /// assert_eq!(array.pop(), Some(2));
493 /// assert_eq!(array.pop(), Some(1));
494 /// assert_eq!(array.pop(), None);
495 /// ```
496 #[inline]
497 pub const fn pop(&mut self) -> Option<T> {
498 if self.is_empty() {
499 None
500 } else {
501 unsafe {
502 // safety: just confirmed there is an element in the array
503 Some(self.pop_unchecked())
504 }
505 }
506 }
507
508 /// remove and return an element from the end of the array.
509 ///
510 /// this is the unsafe version of this method. see [`Self::pop()`] for
511 /// the safe version.
512 ///
513 /// ## safety
514 ///
515 /// there must be at least one element in the array prior to calling
516 /// this method. ie; [`Self::len()`] `!= 0`
517 ///
518 /// ## examples
519 ///
520 /// ```
521 /// # use nyarray::array;
522 /// let mut array = array![1, 2, 3 => 4];
523 ///
524 /// unsafe {
525 /// // safety: array has 3 elements
526 /// assert_eq!(array.pop_unchecked(), 3);
527 /// assert_eq!(array.pop_unchecked(), 2);
528 /// assert_eq!(array.pop_unchecked(), 1);
529 /// // array.pop_unchecked() // UB
530 /// }
531 ///
532 /// assert!(array.is_empty());
533 /// ```
534 #[inline]
535 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
536 pub const unsafe fn pop_unchecked(&mut self) -> T {
537 unsafe {
538 // safety: caller ensures there is at least one element.
539
540 // underflows if no elements
541 let len = self.len() - 1;
542
543 // first set len to new len
544 self.set_len(len);
545
546 core::ptr::read(self.as_ptr().add(len))
547 }
548 }
549
550 /// insert an element into any index of the array, shifting
551 /// all elements after towards the end.
552 ///
553 /// ## examples
554 ///
555 /// ```
556 /// # use nyarray::array;
557 /// let mut array = array![1, 2, 3 => 6];
558 ///
559 /// array.insert(2, 10);
560 /// assert_eq!(array, [1, 2, 10, 3]);
561 ///
562 /// array.insert(0, 20);
563 /// assert_eq!(array, [20, 1, 2, 10, 3]);
564 ///
565 /// array.insert(5, 30);
566 /// assert_eq!(array, [20, 1, 2, 10, 3, 30]);
567 /// ```
568 ///
569 /// ## panics
570 ///
571 /// this method panics if there isn't enough space for another element,
572 /// or if `index` is not `0..self.len()`.
573 /// for a non-panicking version, see [`Self::insert_checked()`].
574 ///
575 /// ```should_panic
576 /// # use nyarray::array;
577 /// let mut array = array![1, 2, 3 => 4];
578 /// array.insert(0, 4); // okay
579 /// array.insert(0, 5); // panics
580 /// ```
581 #[inline]
582 pub fn insert(&mut self, index: usize, element: T) {
583 if self.insert_checked(index, element).is_err() {
584 if index > self.len() {
585 panic!("index out of bounds");
586 } else {
587 panic!("insert exceeds capacity");
588 }
589 }
590 }
591
592 /// insert an element into any index of the array, shifting
593 /// all elements after towards the end. returns Err(T) if there
594 /// is not enough capacity, or if `index` is not `0..=self.len()`.
595 ///
596 /// ## examples
597 ///
598 /// ```
599 /// # fn main() -> Result<(), i32> {
600 /// # use nyarray::array;
601 /// let mut array = array![1, 2, 3 => 6];
602 ///
603 /// array.insert_checked(2, 10)?;
604 /// assert_eq!(array, [1, 2, 10, 3]);
605 ///
606 /// array.insert_checked(0, 20)?;
607 /// assert_eq!(array, [20, 1, 2, 10, 3]);
608 ///
609 /// array.insert_checked(5, 30)?;
610 /// assert_eq!(array, [20, 1, 2, 10, 3, 30]);
611 /// # Ok(())
612 /// # }
613 /// ```
614 #[inline]
615 pub const fn insert_checked(&mut self, index: usize, element: T) -> Result<(), T> {
616 if index > self.len() {
617 return Err(element);
618 }
619
620 if self.len() + 1 > self.capacity() {
621 return Err(element);
622 }
623
624 unsafe {
625 // safety: just confirmed index is in bounds and there is enough capacity
626 self.insert_unchecked(index, element);
627 }
628
629 Ok(())
630 }
631
632 /// insert an element into any index of the array, shifting
633 /// all elements after towards the end.
634 ///
635 /// this is the unsafe version of this method. see [`Self::insert_checked()`] or
636 /// [`Self::insert()`] for safe versions.
637 ///
638 /// ## safety
639 ///
640 /// - there must be enough capacity in the array for at least one more element
641 /// prior to calling this method. ie; [`Self::len()`] `<` [`Self::capacity()`].
642 /// - `index` `<=` [`Self::len()`]
643 ///
644 /// ## examples
645 ///
646 /// ```
647 /// # use nyarray::array;
648 /// let mut array = array![=> 4];
649 ///
650 /// unsafe {
651 /// // safety: array has capacity of 4 elements.
652 /// array.insert_unchecked(0, 1);
653 /// array.insert_unchecked(0, 2);
654 /// array.insert_unchecked(0, 3);
655 /// array.insert_unchecked(0, 4);
656 /// // array.insert_unchecked(0, 5); // UB
657 /// }
658 ///
659 /// assert_eq!(array, [4, 3, 2, 1]);
660 /// ```
661 #[inline]
662 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
663 pub const unsafe fn insert_unchecked(&mut self, index: usize, element: T) {
664 unsafe {
665 let len = self.len();
666
667 let ptr = self.as_mut_ptr().add(index);
668
669 if index != len {
670 core::ptr::copy(ptr, ptr.add(1), len - index);
671 }
672
673 core::ptr::write(ptr, element);
674
675 self.set_len(len + 1);
676 }
677 }
678
679 /// insert an element into any index of the array, moving the element
680 /// that was previously there to the end.
681 ///
682 /// ## examples
683 ///
684 /// ```
685 /// # use nyarray::array;
686 /// let mut array = array![1, 2, 3 => 6];
687 ///
688 /// array.swap_insert(2, 10);
689 /// assert_eq!(array, [1, 2, 10, 3]);
690 ///
691 /// array.swap_insert(0, 20);
692 /// assert_eq!(array, [20, 2, 10, 3, 1]);
693 ///
694 /// array.swap_insert(5, 30);
695 /// assert_eq!(array, [20, 2, 10, 3, 1, 30]);
696 /// ```
697 ///
698 /// ## panics
699 ///
700 /// this method panics if there isn't enough space for another element,
701 /// or if `index` is not `0..=self.len()`.
702 /// for a non-panicking version, see [`Self::swap_insert_checked()`].
703 ///
704 /// ```should_panic
705 /// # use nyarray::array;
706 /// let mut array = array![1, 2, 3 => 4];
707 /// array.swap_insert(0, 4); // okay
708 /// array.swap_insert(0, 5); // panics
709 /// ```
710 #[inline]
711 pub fn swap_insert(&mut self, index: usize, element: T) {
712 if self.swap_insert_checked(index, element).is_err() {
713 if index > self.len() {
714 panic!("index out of bounds");
715 } else {
716 panic!("insert exceeds capacity");
717 }
718 }
719 }
720
721 /// insert an element into any index of the array, moving the element
722 /// that was previously there to the end. returns Err(T) if there
723 /// is not enough capacity, or if `index` is not `0..=self.len()`.
724 ///
725 /// ## examples
726 ///
727 /// ```
728 /// # fn main() -> Result<(), i32> {
729 /// # use nyarray::array;
730 /// let mut array = array![1, 2, 3 => 6];
731 ///
732 /// array.swap_insert_checked(2, 10)?;
733 /// assert_eq!(array, [1, 2, 10, 3]);
734 ///
735 /// array.swap_insert_checked(0, 20)?;
736 /// assert_eq!(array, [20, 2, 10, 3, 1]);
737 ///
738 /// array.swap_insert_checked(5, 30)?;
739 /// assert_eq!(array, [20, 2, 10, 3, 1, 30]);
740 /// # Ok(())
741 /// # }
742 /// ```
743 #[inline]
744 pub const fn swap_insert_checked(&mut self, index: usize, element: T) -> Result<(), T> {
745 if index > self.len() {
746 return Err(element);
747 }
748
749 if self.len() + 1 > self.capacity() {
750 return Err(element);
751 }
752
753 unsafe {
754 // safety: just confirmed index is in bounds and there is enough capacity
755 self.swap_insert_unchecked(index, element);
756 }
757
758 Ok(())
759 }
760
761 /// insert an element into any index of the array, moving the element
762 /// that was previously there to the end.
763 ///
764 /// this is the unsafe version of this method. see [`Self::swap_insert_checked()`]
765 /// or [`Self::swap_insert()`] for safe versions.
766 ///
767 /// ## safety
768 ///
769 /// - there must be enough capacity in the array for at least one more element
770 /// prior to calling this method. ie; [`Self::len()`] `<` [`Self::capacity()`].
771 /// - `index` `<=` [`Self::len()`]
772 ///
773 /// ## examples
774 ///
775 /// ```
776 /// # use nyarray::array;
777 /// let mut array = array![=> 4];
778 ///
779 /// unsafe {
780 /// // safety: array has a capacity of 4
781 /// array.swap_insert_unchecked(0, 1);
782 /// array.swap_insert_unchecked(0, 2);
783 /// array.swap_insert_unchecked(0, 3);
784 /// array.swap_insert_unchecked(0, 4);
785 /// // array.swap_insert_unchecked(0, 5); // UB
786 /// }
787 ///
788 /// assert_eq!(array, [4, 1, 2, 3])
789 /// ```
790 #[inline]
791 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
792 pub const unsafe fn swap_insert_unchecked(&mut self, index: usize, element: T) {
793 unsafe {
794 let len = self.len();
795
796 let ptr = self.as_mut_ptr();
797
798 // safety: caller ensures `index` is in bounds and there is enough
799 // space for another element.
800 let old_ptr = ptr.add(index);
801 let new_ptr = ptr.add(len);
802
803 core::ptr::write(new_ptr, element);
804 core::ptr::swap(old_ptr, new_ptr);
805
806 self.set_len(len + 1);
807 }
808 }
809
810 /// remove and return an element out of any index of the array,
811 /// shifting all elements after towards the start.
812 ///
813 /// ## examples
814 ///
815 /// ```
816 /// # use nyarray::array;
817 /// let mut array = array![1, 2, 3, 4, 5, 6 => 6];
818 ///
819 /// assert_eq!(array.remove(0), 1);
820 /// assert_eq!(array, [2, 3, 4, 5, 6]);
821 ///
822 /// assert_eq!(array.remove(2), 4);
823 /// assert_eq!(array, [2, 3, 5, 6]);
824 ///
825 /// assert_eq!(array.remove(3), 6);
826 /// assert_eq!(array, [2, 3, 5]);
827 /// ```
828 ///
829 /// ## panics
830 ///
831 /// this method panics if `index` is not `0..self.len()`.
832 /// for a non-panicking version, see [`Self::remove_checked()`].
833 ///
834 /// ```should_panic
835 /// # use nyarray::array;
836 /// let mut array = array![1, 2, 3, 4 => 4];
837 /// array.remove(4); // panics
838 /// ```
839 #[inline]
840 pub fn remove(&mut self, index: usize) -> T {
841 if let Some(x) = self.remove_checked(index) {
842 x
843 } else {
844 panic!("index out of bounds");
845 }
846 }
847
848 /// remove and return an element out of any index of the array,
849 /// shifting all elements after towards the start. returns `None`
850 /// if `index` is not `0..self.len()`.
851 ///
852 /// ## examples
853 ///
854 /// ```
855 /// # use nyarray::array;
856 /// let mut array = array![1, 2, 3, 4, 5, 6 => 6];
857 ///
858 /// assert_eq!(array.remove_checked(0), Some(1));
859 /// assert_eq!(array, [2, 3, 4, 5, 6]);
860 ///
861 /// assert_eq!(array.remove_checked(2), Some(4));
862 /// assert_eq!(array, [2, 3, 5, 6]);
863 ///
864 /// assert_eq!(array.remove_checked(3), Some(6));
865 /// assert_eq!(array, [2, 3, 5]);
866 ///
867 /// assert_eq!(array.remove_checked(3), None);
868 /// assert_eq!(array, [2, 3, 5]);
869 /// ```
870 #[inline]
871 pub const fn remove_checked(&mut self, index: usize) -> Option<T> {
872 if index >= self.len() {
873 return None;
874 }
875
876 unsafe {
877 Some(self.remove_unchecked(index))
878 }
879 }
880
881 /// remove and return an element out of any index of the array,
882 /// shifting all elements after towards the start.
883 ///
884 /// this is the unsafe version of this method. see [`Self::remove_checked()`]
885 /// or [`Self::remove()`] for safe versions.
886 ///
887 /// ## safety
888 ///
889 /// - there must be at least one element in the array prior to calling
890 /// this method. ie; [`Self::len()`] `!= 0`
891 /// - `index` `<` [`Self::len()`]
892 ///
893 /// ## examples
894 ///
895 /// ```
896 /// # use nyarray::array;
897 /// let mut array = array![1, 2, 3, 4 => 4];
898 ///
899 /// unsafe {
900 /// // safety: array has 4 elements.
901 /// assert_eq!(array.remove_unchecked(0), 1);
902 /// assert_eq!(array.remove_unchecked(0), 2);
903 /// assert_eq!(array.remove_unchecked(0), 3);
904 /// assert_eq!(array.remove_unchecked(0), 4);
905 /// // array.remove_unchecked(0) // UB
906 /// }
907 ///
908 /// assert!(array.is_empty());
909 /// ```
910 #[inline]
911 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
912 pub const unsafe fn remove_unchecked(&mut self, index: usize) -> T {
913 unsafe {
914 let len = self.len();
915
916 // safety: caller ensures index is in bounds and there is at least one element
917 let ptr = self.as_mut_ptr().add(index);
918
919 let old = core::ptr::read(ptr);
920
921 core::ptr::copy(ptr.add(1), ptr, len - index - 1);
922
923 self.set_len(len - 1);
924
925 old
926 }
927 }
928
929 /// remove and return an element from any index of the array,
930 /// moving the element that was previously at the end to there.
931 ///
932 /// ## examples
933 ///
934 /// ```
935 /// # use nyarray::array;
936 /// let mut array = array![1, 2, 3, 4, 5, 6 => 6];
937 ///
938 /// assert_eq!(array.swap_remove(0), 1);
939 /// assert_eq!(array, [6, 2, 3, 4, 5]);
940 ///
941 /// assert_eq!(array.swap_remove(2), 3);
942 /// assert_eq!(array, [6, 2, 5, 4]);
943 ///
944 /// assert_eq!(array.swap_remove(3), 4);
945 /// assert_eq!(array, [6, 2, 5]);
946 /// ```
947 ///
948 /// ## panics
949 ///
950 /// this method panics if `index` is not `0..=self.len()`.
951 /// for a non-panicking version, see [`Self::swap_remove_checked()`].
952 ///
953 /// ```should_panic
954 /// # use nyarray::array;
955 /// let mut array = array![1, 2, 3, 4 => 4];
956 /// array.swap_remove(4); // panics
957 /// ```
958 #[inline]
959 pub fn swap_remove(&mut self, index: usize) -> T {
960 if let Some(x) = self.swap_remove_checked(index) {
961 x
962 } else {
963 panic!("index out of bounds");
964 }
965 }
966
967 /// remove and return an element from any index of the array,
968 /// moving the element that was previously at the end to there.
969 /// returns `None` if `index` is not `0..self.len()`.
970 ///
971 /// ## examples
972 ///
973 /// ```
974 /// # use nyarray::array;
975 /// let mut array = array![1, 2, 3, 4, 5, 6 => 6];
976 ///
977 /// assert_eq!(array.swap_remove_checked(0), Some(1));
978 /// assert_eq!(array, [6, 2, 3, 4, 5]);
979 ///
980 /// assert_eq!(array.swap_remove_checked(2), Some(3));
981 /// assert_eq!(array, [6, 2, 5, 4]);
982 ///
983 /// assert_eq!(array.swap_remove_checked(3), Some(4));
984 /// assert_eq!(array, [6, 2, 5]);
985 ///
986 /// assert_eq!(array.swap_remove_checked(3), None);
987 /// assert_eq!(array, [6, 2, 5]);
988 /// ```
989 #[inline]
990 pub const fn swap_remove_checked(&mut self, index: usize) -> Option<T> {
991 let len = self.len();
992 if index >= len {
993 return None;
994 }
995
996 unsafe {
997 Some(self.swap_remove_unchecked(index))
998 }
999 }
1000
1001 /// remove and return an element from any index of the array,
1002 /// moving the element that was previously at the end to there.
1003 /// returns `None` if `index` is not `0..self.len()`.
1004 ///
1005 /// this is the unsafe version of this method. see [`Self::swap_remove_checked()`]
1006 /// or [`Self::swap_remove()`] for safe versions.
1007 ///
1008 /// ## safety
1009 ///
1010 /// - there must be at least one element in the array prior to calling
1011 /// this method. ie; [`Self::len()`] `!= 0`
1012 /// - `index` `<` [`Self::len()`]
1013 ///
1014 /// ## examples
1015 ///
1016 /// ```
1017 /// # use nyarray::array;
1018 /// let mut array = array![1, 2, 3, 4 => 4];
1019 ///
1020 /// unsafe {
1021 /// // safety: array has 4 elements.
1022 /// assert_eq!(array.swap_remove_unchecked(0), 1);
1023 /// assert_eq!(array.swap_remove_unchecked(0), 4);
1024 /// assert_eq!(array.swap_remove_unchecked(0), 3);
1025 /// assert_eq!(array.swap_remove_unchecked(0), 2);
1026 /// // array.swap_remove_unchecked(0) // UB
1027 /// }
1028 ///
1029 /// assert!(array.is_empty());
1030 /// ```
1031 #[inline]
1032 #[expect(clippy::missing_safety_doc, reason = "there is a safety doc, not sure why the lint still generates")]
1033 pub const unsafe fn swap_remove_unchecked(&mut self, index: usize) -> T {
1034 unsafe {
1035 let len = self.len();
1036
1037 let ptr = self.as_mut_ptr();
1038
1039 // safety: caller ensures index is in bounds and there is at least one element
1040 let old = core::ptr::read(ptr.add(index));
1041
1042 core::ptr::copy(ptr.add(len - 1), ptr.add(index), 1);
1043
1044 self.set_len(len - 1);
1045
1046 old
1047 }
1048 }
1049}
1050
1051impl<const N: usize, T> Drop for Array<N, T> {
1052 fn drop(&mut self) {
1053 self.clear();
1054 }
1055}
1056
1057impl<const N: usize, T> Default for Array<N, T> {
1058 fn default() -> Self {
1059 Self::new()
1060 }
1061}
1062
1063impl<const N: usize, T: Clone> Clone for Array<N, T> {
1064 fn clone(&self) -> Self {
1065 self.iter().cloned().collect()
1066 }
1067}
1068
1069impl<const N: usize, T> AsRef<[T]> for Array<N, T> {
1070 fn as_ref(&self) -> &[T] {
1071 self.as_slice()
1072 }
1073}
1074
1075impl<const N: usize, T> AsMut<[T]> for Array<N, T> {
1076 fn as_mut(&mut self) -> &mut [T] {
1077 self.as_mut_slice()
1078 }
1079}
1080
1081impl<const N: usize, T> core::borrow::Borrow<[T]> for Array<N, T> {
1082 fn borrow(&self) -> &[T] {
1083 self.as_slice()
1084 }
1085}
1086
1087impl<const N: usize, T> core::borrow::BorrowMut<[T]> for Array<N, T> {
1088 fn borrow_mut(&mut self) -> &mut [T] {
1089 self.as_mut_slice()
1090 }
1091}
1092
1093impl<const N: usize, T> core::ops::Deref for Array<N, T> {
1094 type Target = [T];
1095 fn deref(&self) -> &Self::Target {
1096 self.as_slice()
1097 }
1098}
1099
1100impl<const N: usize, T> core::ops::DerefMut for Array<N, T> {
1101 fn deref_mut(&mut self) -> &mut Self::Target {
1102 self.as_mut_slice()
1103 }
1104}
1105
1106impl<const N: usize, T, I: core::slice::SliceIndex<[T]>> core::ops::Index<I> for Array<N, T> {
1107 type Output = I::Output;
1108 fn index(&self, index: I) -> &Self::Output {
1109 core::ops::Index::index(self.as_slice(), index)
1110 }
1111}
1112
1113impl<const N: usize, T, I: core::slice::SliceIndex<[T]>> core::ops::IndexMut<I> for Array<N, T> {
1114 fn index_mut(&mut self, index: I) -> &mut Self::Output {
1115 core::ops::IndexMut::index_mut(self.as_mut_slice(), index)
1116 }
1117}
1118
1119impl<const N: usize, T> Extend<T> for Array<N, T> {
1120 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1121 for i in iter {
1122 if self.push_checked(i).is_err() {
1123 break;
1124 }
1125 }
1126 }
1127}
1128
1129impl<'a, const N: usize, T: Copy> Extend<&'a T> for Array<N, T> {
1130 fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
1131 for i in iter {
1132 if self.push_checked(*i).is_err() {
1133 break;
1134 }
1135 }
1136 }
1137}
1138
1139
1140#[doc(hidden)]
1141pub fn from_elem<const N: usize, T: Clone>(elem: T, n: usize) -> Array<N, T> {
1142 let mut array = Array::new();
1143 for _ in 0..n {
1144 array.push(elem.clone());
1145 }
1146 array
1147}
1148
1149
1150/// iterator for [`Array`].
1151pub struct IntoIter<const N: usize, T> {
1152 inner: [core::mem::MaybeUninit<T>; N],
1153 cur: usize,
1154 end: usize,
1155}
1156
1157impl<const N: usize, T> Drop for IntoIter<N, T> {
1158 fn drop(&mut self) {
1159 while self.cur != self.end {
1160 unsafe {
1161 self.inner.get_unchecked_mut(self.cur).assume_init_drop();
1162 self.cur += 1;
1163 }
1164 }
1165 }
1166}
1167
1168impl<const N: usize, T> Iterator for IntoIter<N, T> {
1169 type Item = T;
1170
1171 fn next(&mut self) -> Option<Self::Item> {
1172 if self.cur == self.end {
1173 return None;
1174 }
1175 unsafe {
1176 let out = self.inner.get_unchecked(self.cur).assume_init_read();
1177 self.cur += 1;
1178 Some(out)
1179 }
1180 }
1181}
1182
1183impl<const N: usize, T> DoubleEndedIterator for IntoIter<N, T> {
1184 fn next_back(&mut self) -> Option<Self::Item> {
1185 if self.cur == self.end {
1186 return None;
1187 }
1188 unsafe {
1189 self.end -= 1;
1190 Some(self.inner.get_unchecked(self.end).assume_init_read())
1191 }
1192 }
1193}
1194
1195impl<const N: usize, T> IntoIterator for Array<N, T> {
1196 type IntoIter = IntoIter<N, T>;
1197 type Item = T;
1198
1199 fn into_iter(self) -> Self::IntoIter {
1200 let (buf, len) = self.into_parts_len();
1201 IntoIter {
1202 inner: buf,
1203 cur: 0,
1204 end: len,
1205 }
1206 }
1207}
1208
1209impl<'a, const N: usize, T> IntoIterator for &'a Array<N, T> {
1210 type IntoIter = core::slice::Iter<'a, T>;
1211 type Item = &'a T;
1212
1213 fn into_iter(self) -> Self::IntoIter {
1214 self.as_slice().iter()
1215 }
1216}
1217
1218impl<'a, const N: usize, T> IntoIterator for &'a mut Array<N, T> {
1219 type IntoIter = core::slice::IterMut<'a, T>;
1220 type Item = &'a mut T;
1221
1222 fn into_iter(self) -> Self::IntoIter {
1223 self.as_mut_slice().iter_mut()
1224 }
1225}
1226
1227impl<const N: usize, T> FromIterator<T> for Array<N, T> {
1228 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1229 let mut out = Self::new();
1230 out.extend(iter);
1231 out
1232 }
1233}
1234
1235
1236impl<const N: usize, T: PartialOrd> PartialOrd for Array<N, T> {
1237 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
1238 PartialOrd::partial_cmp(self.as_slice(), other.as_slice())
1239 }
1240}
1241
1242impl<const N: usize, T: Eq> Eq for Array<N, T> {}
1243
1244impl<const N: usize, T: Ord> Ord for Array<N, T> {
1245 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
1246 Ord::cmp(self.as_slice(), other.as_slice())
1247 }
1248}
1249
1250impl<const N: usize, const M: usize, T: PartialEq> PartialEq<Array<M, T>> for Array<N, T> {
1251 fn eq(&self, other: &Array<M, T>) -> bool {
1252 PartialEq::eq(self.as_slice(), other.as_slice())
1253 }
1254}
1255
1256impl<const N: usize, T: PartialEq> PartialEq<&[T]> for Array<N, T> {
1257 fn eq(&self, other: &&[T]) -> bool {
1258 PartialEq::eq(self.as_slice(), *other)
1259 }
1260}
1261
1262impl<const N: usize, T: PartialEq> PartialEq<&mut [T]> for Array<N, T> {
1263 fn eq(&self, other: &&mut [T]) -> bool {
1264 PartialEq::eq(self.as_slice(), *other)
1265 }
1266}
1267
1268impl<const N: usize, const M: usize, T: PartialEq> PartialEq<[T; M]> for Array<N, T> {
1269 fn eq(&self, other: &[T; M]) -> bool {
1270 PartialEq::eq(self.as_slice(), other.as_slice())
1271 }
1272}
1273
1274impl<const N: usize, const M: usize, T: PartialEq> PartialEq<&[T; M]> for Array<N, T> {
1275 fn eq(&self, other: &&[T; M]) -> bool {
1276 PartialEq::eq(self.as_slice(), other.as_slice())
1277 }
1278}
1279
1280impl<const N: usize, T: core::fmt::Debug> core::fmt::Debug for Array<N, T> {
1281 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1282 core::fmt::Debug::fmt(self.as_slice(), f)
1283 }
1284}
1285
1286
1287/// create an [`Array`].
1288///
1289/// like `vec!`, `array!` has similar syntax as Rust array expressions, with
1290/// the addition of allowing one to specify the capacity of the `Array`
1291/// by appending an `=>`:
1292///
1293/// ```
1294/// # use nyarray::array;
1295/// let array = array![1, 2, 3 => 6]; // capacity of 6 elements
1296/// assert_eq!(array[0], 1);
1297/// assert_eq!(array[1], 2);
1298/// assert_eq!(array[2], 3);
1299/// ```
1300#[macro_export]
1301macro_rules! array {
1302 () => {
1303 $crate::array::Array::new()
1304 };
1305 (=> $cap:literal) => {
1306 $crate::array::Array::<$cap, _>::new()
1307 };
1308 ($elem:expr; $n:expr) => {
1309 $crate::array::from_elem($elem, $n)
1310 };
1311 ($elem:expr; $n:expr => $cap:literal) => {
1312 $crate::array::from_elem::<$cap, _>($elem, $n)
1313 };
1314 ($($x:expr),+ $(,)?) => {
1315 $crate::array::Array::from_parts([$($x),+])
1316 };
1317 ($($x:expr),+ $(,)? => $cap:literal) => {
1318 $crate::array::Array::<$cap, _>::from_parts([$($x),+])
1319 };
1320}
1321
1322
1323#[cfg(test)]
1324mod test {
1325 extern crate std;
1326
1327 #[test]
1328 fn test_drop() {
1329 static mut NUM: u32 = 0;
1330
1331 struct Box<T> {
1332 _inner: std::boxed::Box<T>,
1333 }
1334 impl<T> Box<T> {
1335 fn new(inner: T) -> Self {
1336 Self {
1337 _inner: std::boxed::Box::new(inner),
1338 }
1339 }
1340 }
1341 impl<T> Drop for Box<T> {
1342 fn drop(&mut self) {
1343 unsafe {
1344 NUM += 1;
1345 }
1346 }
1347 }
1348
1349 let array = array![Box::new(1), Box::new(2), Box::new(3) => 4];
1350
1351 drop(array);
1352
1353 assert_eq!(unsafe { NUM }, 3);
1354
1355 let array = array![Box::new(1), Box::new(2), Box::new(3) => 4];
1356 let mut iter = array.into_iter();
1357 iter.next();
1358
1359 drop(iter);
1360
1361 assert_eq!(unsafe { NUM }, 6);
1362 }
1363
1364 #[test]
1365 fn test_iter() {
1366 let array = array![std::boxed::Box::new(1) => 4];
1367 let _ = array.iter().cloned().collect::<crate::array::Array<4, _>>();
1368 }
1369}
1370