diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5db9525..78cf11e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: pull_request: branches: - master - - + name: Continuous integration jobs: @@ -96,7 +96,6 @@ jobs: command: clippy args: --all-targets --all-features -- -D warnings - - name: miri setup uses: actions-rs/cargo@v1 if: matrix.rust == 'miri' diff --git a/Cargo.toml b/Cargo.toml index 14a5fe9..c1b0b87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,9 @@ alloc = [] # - `exact_size_is_empty` (for implementing `<{Chunks,IterMove} as ExactSizeIterator>::is_empty` more effective) nightly = [] -array-impls-33-128 = [] -array-impls-129-256 = [] +[[example]] +name = "array_stack" +required-features = ["nightly"] [package.metadata.docs.rs] all-features = true diff --git a/README.md b/README.md index 4c3f408..b9e50d7 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ _Compiler support: requires rustc 1.41+_ ## Examples ```rust -use arraylib::{Array, ArrayMap, ArrayExt}; +use arraylib::Array; // Array creation let arr = <[_; 11]>::unfold(1, |it| { let res = *it; @@ -27,7 +27,7 @@ let arr = <[_; 11]>::unfold(1, |it| { }); // Mapping -let arr = arr.map(|it| it * 2); +let arr = arr.lift(|it| it * 2); assert_eq!(arr, [2, -4, 8, -16, 32, -64, 128, -256, 512, -1024, 2048]); // By-value iterator diff --git a/examples/array_stack.rs b/examples/array_stack.rs new file mode 100644 index 0000000..d3394b2 --- /dev/null +++ b/examples/array_stack.rs @@ -0,0 +1,129 @@ +//! An example of using `Continuous` to build an array-based collection. +//! +//! All operations (except creation and unsizing) are defined on +//! `ArrayStack<[T]>` to make the codegen impact smaller (hoping for faster +//! compilation and smaller binaries). +//! +//! All nightly features are used only to make all operations `const`. Without +//! `const` restrictions this example works on stable. +//! +//! The example should also work without `std`/`alloc`. +#![feature(const_mut_refs)] +#![feature(const_maybe_uninit_as_ptr)] +#![feature(const_ptr_read)] +#![feature(const_raw_ptr_deref)] +#![feature(const_slice_from_raw_parts)] +#![feature(label_break_value)] +#![allow(clippy::redundant_pattern_matching)] + +use core::mem::MaybeUninit; + +use arraylib::Continuous; + +#[repr(C)] +pub struct ArrayStack { + len: usize, + inner: S::Uninit, +} + +impl ArrayStack<[T; N]> { + const U: MaybeUninit = MaybeUninit::uninit(); + + pub const fn new() -> Self { + Self { + len: 0, + inner: [Self::U; N], + } + } + + pub const fn unsize(&mut self) -> &mut ArrayStack<[T]> { + use core::ptr::slice_from_raw_parts_mut; + + // For some reason `ArrayStack<[T]>` doesn't implement `Pointee`, so it's + // impossible to use `core::ptr::from_raw_parts_mut` here. + // + // This function uses `slice_from_raw_parts_mut` to create a pointer with + // desired metadata. + let ptr = slice_from_raw_parts_mut(self as *mut Self as *mut T, N); + + // ## Safety + // + // `ArrayStack<[T; N]>` and `ArrayStack<[T]>` are guaranteed to have the same + // layout. `ptr` contains a proper metadata (as long as slice metadata is the + // same as a dst with a slice metadata) and is derived from a mutable reference. + unsafe { &mut *(ptr as *mut ArrayStack<[T]>) } + } +} +impl ArrayStack<[T]> { + pub const fn push(&mut self, item: T) -> Result<(), T> { + if self.len == self.inner.len() { + Err(item) + } else { + self.inner[self.len] = MaybeUninit::new(item); + self.len += 1; + Ok(()) + } + } + + pub const fn pop(&mut self) -> Option { + match self.len { + 0 => None, + + // ## Safety + // + // `self.inner[..self.len]` is always initialized + _ => unsafe { + self.len -= 1; + Some(self.inner[self.len].as_ptr().read()) + }, + } + } + + pub const fn peek(&self) -> Option<&T> { + match self.len { + 0 => None, + + // ## Safety + // + // `self.inner[..self.len]` is always initialized + _ => unsafe { Some(&*self.inner[self.len - 1].as_ptr()) }, + } + } +} + +const TEST: i32 = 'a: { + let mut stack = ArrayStack::<[i32; 2]>::new(); + + if let Err(_) = stack.unsize().push(1) { + break 'a -1; + } + + let stack = stack.unsize(); + + let p0 = match stack.peek() { + None => break 'a -2, + Some(&x) => x, + }; + + if let Err(_) = stack.push(2) { + break 'a -3; + } + + let p1 = match stack.peek() { + None => break 'a -4, + Some(&x) => x, + }; + + if let Ok(()) = stack.push(3) { + break 'a -5; + } + + match (stack.pop(), stack.pop()) { + (Some(a), Some(b)) => p0 + p1 + a + b, + _ => -6, + } +}; + +fn main() { + assert_eq!(TEST, 6); +} diff --git a/src/array.rs b/src/array.rs index 74a75eb..20f635a 100644 --- a/src/array.rs +++ b/src/array.rs @@ -1,6 +1,11 @@ -use core::mem::MaybeUninit; +use core::{convert::Infallible, hint::unreachable_unchecked, mem::MaybeUninit}; -use crate::util::transmute::extremely_unsafe_transmute; +use crate::{ + continuous::Continuous, + iter::IteratorExt, + util::{init, transmute::extremely_unsafe_transmute}, + SizeError, +}; /// Represent array of _some_ size. E.g.: `[u8; 32]`, `[&str; 8]`, `[T; N]`. /// @@ -20,60 +25,69 @@ use crate::util::transmute::extremely_unsafe_transmute; /// /// It is **highly not recommended** to implement this trait on your type unless /// you **really** know what you are doing. -pub unsafe trait Array: Sized { - /// Type of the Items in the array. i.e. - /// ``` - /// # use arraylib::Array; fn dummy() where - /// [T; 4]: Array - /// # {} - /// ``` - type Item; - - /// Same array but item is wrapped with - /// [`MaybeUninit<_>`](core::mem::MaybeUninit). - /// ``` - /// # use arraylib::Array; fn dummy() where - /// [T; 4]: Array; 4]> - /// # {} - /// ``` - type Maybe: Array>; - - /// Size of the array. - /// - /// ## Example +pub unsafe trait Array: Sized + Continuous +where + ::Uninit: Sized, +{ + /// Maps elements of the array /// + /// ## Examples /// ``` /// use arraylib::Array; /// - /// assert_eq!(<[(); 0]>::SIZE, 0); - /// assert_eq!(<[(); 2]>::SIZE, 2); + /// let arr = [1, 2, 3, 4, 5]; + /// let res = arr.lift(|x| 2i32.pow(x)); + /// assert_eq!(res, [2, 4, 8, 16, 32]) /// ``` - const SIZE: usize; - - /// Extracts a slice containing the entire array. /// - /// ## Example + /// **NOTE**: it's highly recommended to use iterators when you need to + /// perform more that one operation (e.g. map + as_ref) because iterators + /// are lazy and `ArrayMap` isn't. + fn lift(self, f: F) -> [U; N] + where + F: FnMut(Self::Item) -> U; + + /// Convert `&self` to `[&T; N]` (where `T = Self::Item, N = Self::Size`) /// + /// ## Examples /// ``` /// use arraylib::Array; /// - /// let array = [1, 2, 3]; - /// assert_eq!(array.as_slice()[1..], [2, 3]); + /// let arr = [0, 1, 2, 3]; + /// let ref_arr = arr.as_refs(); + /// assert_eq!(ref_arr, [&0, &1, &2, &3]); + /// assert_eq!(arr, [0, 1, 2, 3]); /// ``` - fn as_slice(&self) -> &[Self::Item]; - - /// Extracts a mutable slice of the entire array. /// - /// ## Example + /// **NOTE**: it's highly recommended to use iterators when you need to + /// perform more that one operation (e.g. map + as_ref) because iterators + /// are lazy and `ArrayAsRef` isn't. /// + /// See also: [`as_mut_refs`](crate::Array::as_mut_refs) + fn as_refs(&self) -> [&Self::Item; N]; + + /// Convert `&mut self` to `[&mut T; N]` (where `T = Self::Item, N = + /// Self::Size`) + /// + /// ## Examples /// ``` /// use arraylib::Array; /// - /// let mut array = [1, 0, 1]; - /// array.as_mut_slice()[1] = 2; - /// assert_eq!(array, [1, 2, 1]); + /// let mut arr = [0, 1, 2, 3]; + /// let ref_arr = arr.as_mut_refs(); + /// assert_eq!(ref_arr, [&mut 0, &mut 1, &mut 2, &mut 3]); + /// assert_eq!(arr, [0, 1, 2, 3]); /// ``` - fn as_mut_slice(&mut self) -> &mut [Self::Item]; + /// + /// **NOTE**: it's highly recommended to use iterators when you need to + /// perform more that one operation (e.g. map + as_ref) because iterators + /// are lazy and `ArrayAsRef` isn't. + /// + /// See also: [`as_refs`](crate::Array::as_refs) + fn as_mut_refs(&mut self) -> [&mut Self::Item; N]; + + /// + fn iter_move(self) -> core::array::IntoIter; /// Create new array, filled with elements returned by `f`. If `f` return /// `Err` then this method also return `Err`. @@ -156,52 +170,20 @@ pub unsafe trait Array: Sized { /// ## Examples /// /// ``` - /// use arraylib::{Array, ArrayExt}; + /// use arraylib::Array; /// use std::iter::once; /// /// let iter = [-2, -1, 0, 1, 2].iter_move().filter(|it| it % 2 == 0); - /// let arr = <[i32; 2]>::try_from_iter(iter); + /// let arr = <[i32; 2]>::from_iter(iter); /// assert_eq!(arr, Some([-2, 0])); /// - /// let arr = <[i32; 2]>::try_from_iter(once(0)); + /// let arr = <[i32; 2]>::from_iter(once(0)); /// assert_eq!(arr, None); /// ``` - fn try_from_iter(iter: I) -> Option + fn from_iter(iter: I) -> Option where I: IntoIterator; - /// Creates an array from an iterator. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::{Array, ArrayExt}; - /// - /// let iter = [-2, -1, 0, 1, 2].iter_move().filter(|it| it % 2 == 0); - /// let arr = <[i32; 2]>::from_iter(iter); - /// - /// assert_eq!(arr, [-2, 0]); - /// ``` - /// - /// ## Panics - /// - /// If there are not enough elements to fill the array: - /// - /// ```should_panic - /// use arraylib::Array; - /// use std::iter::once; - /// - /// let _ = <[i32; 2]>::from_iter(once(0)); - /// ``` - #[inline] - fn from_iter(iter: I) -> Self - where - I: IntoIterator, - { - Self::try_from_iter(iter) - .expect("there weren't enough elements to fill an array of that size") - } - /// Converts self into `[MaybeUninit; Self::Size]`. This /// function is used internally in this crate for some unsafe code. /// @@ -213,7 +195,7 @@ pub unsafe trait Array: Sized { /// let _: [MaybeUninit; 3] = [true, false, false].into_uninit(); /// ``` #[inline] - fn into_uninit(self) -> Self::Maybe { + fn into_uninit(self) -> Self::Uninit { // Note: copy-pasted from https://doc.rust-lang.org/nightly/src/core/array/iter.rs.html // ## Safety @@ -228,7 +210,7 @@ pub unsafe trait Array: Sized { // // With that (and the guarantees of the array trait), this // initialization satisfies the invariants. - unsafe { extremely_unsafe_transmute::(self) } + unsafe { extremely_unsafe_transmute::(self) } } /// Creates uninitialized array of [`MaybeUninit`]. @@ -248,7 +230,7 @@ pub unsafe trait Array: Sized { // is an array of `MaybeUninit` that doesn't require initialization, so // everything is ok #[allow(clippy::uninit_assumed_init)] - fn uninit() -> Self::Maybe { + fn uninit() -> Self::Uninit { unsafe { // ## Safety // @@ -306,7 +288,7 @@ pub unsafe trait Array: Sized { /// // `arr[3]` had not been initialized yet, so this last line caused undefined behavior. /// ``` #[inline] - unsafe fn assume_init(uninit: Self::Maybe) -> Self { + unsafe fn assume_init(uninit: Self::Uninit) -> Self { // # Unsafety // // Array trait guarantees that Self::Maybe is an array of the same size @@ -318,21 +300,392 @@ pub unsafe trait Array: Sized { // initialized state. // // So this is safe if all items in `uninit` array are initialized. - extremely_unsafe_transmute::(uninit) + extremely_unsafe_transmute::(uninit) } /// Converts `self` into `Box<[Self::Item]>` #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] fn into_boxed_slice(self) -> alloc::boxed::Box<[Self::Item]>; -} -unsafe impl Array for [T; 0] { - type Item = T; - type Maybe = [MaybeUninit; 0]; + /// ## Example + /// ``` + /// use arraylib::Array; + /// + /// let arr: [_; 6] = [1, 2, 3].concat_arr([4, 5, 6]); + /// assert_eq!(arr, [1, 2, 3, 4, 5, 6]) + /// ``` + /// + /// ## Panics + /// + /// Panics if `Self::SIZE` + `A::SIZE` != `R::SIZE`: + /// + /// ```should_panic + /// use arraylib::Array; + /// + /// let arr: [_; 4] = [1, 2, 3].concat_arr([4, 5, 6]); + /// ``` + #[inline] + fn concat_arr(self, other: [Self::Item; M]) -> [Self::Item; R] { + unsafe { + // Because of lack of const generics we need to assert this at runtime :( + assert_eq!(N + M, R); + + #[repr(C, packed)] + struct Both(Slf, A); + + // ## Safety + // + // We know that all `Self`, `A` and `R` are arrays. + // Also we know that `Self::SIZE + A::SIZE == R::SIZE`, that means that we can + // concat `Self` with `A` and we'll obtain `R`. + // + // Because of fact that all types are arrays (and fact that `Both` is + // `#[repr(C, packed)]`), we know that `Both` is equal to `R`, so we + // can safely transmute one into another. + let both = Both(self, other); + extremely_unsafe_transmute::, [Self::Item; R]>(both) + } + } + + /// Splits self into 2 arrays + /// + /// ## Example + /// ``` + /// use arraylib::Array; + /// + /// let arr = [1, 2, 3, 4, 5]; + /// let (head, tail) = arr.split_arr::<2, 3>(); + /// + /// assert_eq!(head, [1, 2]); + /// assert_eq!(tail, [3, 4, 5]); + /// ``` + #[inline] + fn split_arr(self) -> ([Self::Item; L], [Self::Item; R]) { + unsafe { + // Because of lack of const generics we need to assert this in runtime :( + assert_eq!(N, L + R); + + #[repr(C, packed)] + struct Both(A, B); + + // ## Safety + // + // We know that all `Self`, `A` and `B` are arrays. + // Also we know that `Self::SIZE, A::SIZE + B::SIZE`, that means that we can + // split `Self` into `A` and `B`. + // + // Because of fact that all types are arrays (and fact that `Both` is + // `#[repr(C, packed)]`), we know that `Both` is equal to `R`, so we + // can safely transmute one into another. + let Both(a, b): Both<[Self::Item; L], [Self::Item; R]> = + extremely_unsafe_transmute::>(self); + + (a, b) + } + } + + crate::if_alloc! { + /// Converts `self` into a vector without clones. + /// + /// The resulting vector can be converted back into a box via + /// `Vec`'s `into_boxed_slice` method. + /// + /// ## Examples + /// + /// ``` + /// use arraylib::Array; + /// + /// let s = [10, 40, 30]; + /// let x = s.into_vec(); + /// // `s` cannot be used anymore because it has been converted into `x`. + /// + /// assert_eq!(x, vec![10, 40, 30]); + /// ``` + /// + /// See also: [`[T]::into_vec`](https://doc.rust-lang.org/std/primitive.slice.html#method.into_vec) + #[inline] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn into_vec(self) -> alloc::vec::Vec { + self.into_boxed_slice().into_vec() + } + } + + /// Create array from slice. Return `Err(())` if `slice.len != Self::SIZE`. + /// + /// ## Examples + /// ``` + /// use arraylib::Array; + /// + /// let slice = &[1, 2, 3]; + /// let arr = <[i32; 3]>::from_slice(slice); + /// assert_eq!(arr, Ok([1, 2, 3])); + /// ``` + /// + /// ``` + /// # use arraylib::{Array, SizeError}; + /// let slice = &[1, 2, 3, 4]; + /// let arr = <[i32; 2]>::from_slice(slice); + /// + /// let SizeError { + /// expected, found, .. + /// } = arr.unwrap_err(); + /// assert_eq!(expected, 2); + /// assert_eq!(found, 4); + /// ``` + #[inline] + fn from_slice(slice: &[Self::Item]) -> Result + where + Self::Item: Copy, + { + if slice.len() == N { + Ok(Self::from_iter(slice.iter().copied()).unwrap()) + } else { + Err(SizeError { + expected: N, + found: slice.len(), + }) + } + } + + /// Create array from slice. Return `Err(())` if `slice.len != Self::SIZE`. + /// + /// Same as [`from_slice`](crate::Array::from_slice), but doesn't require + /// items to be `Copy`, instead only require elements to be `Clone` + /// + /// ## Examples + /// + /// ``` + /// use arraylib::Array; + /// + /// let slice = &[String::from("hi"), 123.to_string(), String::new()]; + /// let arr = <[String; 3]>::clone_from_slice(slice); + /// assert_eq!( + /// arr, + /// Ok([String::from("hi"), 123.to_string(), String::new()]) + /// ); + /// ``` + #[inline] + fn clone_from_slice(slice: &[Self::Item]) -> Result + where + Self::Item: Clone, + { + if slice.len() == N { + Ok(Self::from_iter(slice.iter().cloned()).unwrap()) + } else { + Err(SizeError { + expected: N, + found: slice.len(), + }) + } + } + + /// Safely cast `&[T]` to `&Self` (`[T; N]`) + /// + /// ## Panics + /// + /// Panics if size of `slice` is less than size of `Self`. + /// + /// ## Examples + /// + /// ``` + /// use arraylib::Array; + /// + /// let vec = vec![1, 0, 2, 14]; + /// assert_eq!(<[i32; 4]>::ref_cast(&vec[..]), &[1, 0, 2, 14]); + /// ``` + /// + /// ```should_panic + /// # use arraylib::Array; + /// // panics + /// <[i32; 4]>::ref_cast(&[1, 2][..]); + /// ``` + #[inline] + fn ref_cast(slice: &[Self::Item]) -> &Self { + match Self::try_ref_cast(slice) { + Ok(x) => x, + Err(_) => size_expectation_failed(), + } + } + + /// Safely cast `&mut [T]` to `&mut Self` (`[T; N]`) + /// + /// ## Panics + /// + /// Panics if size of `slice` is less than size of `Self`. + /// + /// ## Examples + /// + /// ``` + /// use arraylib::{Array, SizeError}; + /// + /// let mut vec = vec![1, 0, 2, 14]; + /// assert_eq!(<[i32; 4]>::mut_cast(&mut vec[..]), &mut [1, 0, 2, 14]); + /// ``` + /// + /// ```should_panic + /// # use arraylib::Array; + /// // panics + /// <[i32; 4]>::mut_cast(&mut [1, 2][..]); + /// ``` + #[inline] + fn mut_cast(slice: &mut [Self::Item]) -> &mut Self { + match Self::try_mut_cast(slice) { + Ok(x) => x, + Err(_) => size_expectation_failed(), + } + } + + /// Safely cast `&[T]` to `&Self` (`[T; N]`) + /// + /// ## Errors + /// + /// If size of `slice` is less than size of `Self`, then an error is + /// returned. + /// + /// ## Examples + /// + /// ``` + /// use arraylib::{Array, SizeError}; + /// + /// let vec = vec![1, 0, 2, 14]; + /// assert_eq!(<[i32; 4]>::try_ref_cast(&vec[..]), Ok(&[1, 0, 2, 14])); + /// assert_eq!(<[i32; 4]>::try_ref_cast(&vec[1..=2]), Err(&[0, 2][..])); + /// ``` + #[inline] + fn try_ref_cast(slice: &[Self::Item]) -> Result<&Self, &[Self::Item]> { + unsafe { + if slice.len() >= N { + Ok(Self::ref_cast_unchecked(slice)) + } else { + Err(slice) + } + } + } + + /// Safely cast `&mut [T]` to `&mut Self` (`[T; N]`) + /// + /// ## Errors + /// + /// If size of `slice` is less than size of `Self`, then an error is + /// returned. + /// + /// ## Examples + /// + /// ``` + /// use arraylib::{Array, SizeError}; + /// + /// let mut vec = vec![1, 0, 2, 14]; + /// assert_eq!( + /// <[i32; 4]>::try_mut_cast(&mut vec[..]), + /// Ok(&mut [1, 0, 2, 14]) + /// ); + /// assert_eq!( + /// <[i32; 4]>::try_mut_cast(&mut vec[1..=2]), + /// Err(&mut [0, 2][..]) + /// ); + /// ``` + #[inline] + fn try_mut_cast(slice: &mut [Self::Item]) -> Result<&mut Self, &mut [Self::Item]> { + unsafe { + if slice.len() >= N { + Ok(Self::mut_cast_unchecked(slice)) + } else { + Err(slice) + } + } + } + + /// Unsafety cast `&[T]` to `&Self` (`[T; N]`) + /// + /// ## Safety + /// + /// To safely call this function you need to ensure that size of slice is + /// not less than the size of array: `slice.len() >= Self::SIZE` + /// + /// ## Examples + /// + /// ok usage: + /// ``` + /// use arraylib::Array; + /// + /// let vec = vec![1, 0, 2, 14]; + /// + /// let _: &[i32; 4] = unsafe { + /// // Safe because we know that size of `vec` is equal 4 + /// <[i32; 4]>::ref_cast_unchecked(&vec[..]) + /// }; + /// ``` + /// **wrong** (UB) usage: + /// ```no_run + /// use arraylib::Array; + /// + /// let vec = vec![1, 0, 2, 14]; + /// + /// let _: &[i32; 4] = unsafe { + /// // size of slice borrowed from `vec` is not equal to 4 so this is UB + /// <[i32; 4]>::ref_cast_unchecked(&vec[1..]) + /// }; + /// ``` + #[inline] + unsafe fn ref_cast_unchecked(slice: &[Self::Item]) -> &Self { + // ## (Un)Safety + // + // Slice and array of the same size must have the same ABI, so we can safely get + // `&[T; N]` from `&[A::Item]` **if `slice.len()` >= N**. Here it is not + // checked, so this method is unsafe. + // + // We can't transmute slice ref directly to array ref because + // first is fat pointer and second is not. + &*(slice.as_ptr() as *const Self) + } - const SIZE: usize = 0; + /// Unsafety cast `&mut [T]` to `&mut Self` (`[T; N]`) + /// + /// ## Safety + /// + /// To safely call this function you need to ensure that size of slice is + /// not less than the size of array: `slice.len() >= Self::SIZE` + /// + /// ## Examples + /// + /// ok usage: + /// ``` + /// use arraylib::Array; + /// + /// let mut vec = vec![1, 0, 2, 14]; + /// + /// let _: &[i32; 4] = unsafe { + /// // Safe because we know that size of `vec` is equal 4 + /// <[i32; 4]>::ref_cast_unchecked(&mut vec[..]) + /// }; + /// ``` + /// **wrong** (UB) usage: + /// ```no_run + /// use arraylib::Array; + /// + /// let mut vec = vec![1, 0, 2, 14]; + /// + /// let _: &[i32; 4] = unsafe { + /// // size of slice borrowed from `vec` is not equal to 4 so this is UB + /// <[i32; 4]>::ref_cast_unchecked(&mut vec[1..]) + /// }; + /// ``` + #[inline] + unsafe fn mut_cast_unchecked(slice: &mut [Self::Item]) -> &mut Self { + // ## (Un)Safety + // + // Slice and array of the same size must have the same ABI, so we can safely get + // `&mut [T; N]` from `&mut [A::Item]` **if `slice.len()` >= N**. Here it is not + // checked, so this method is unsafe. + // + // We can't transmute slice ref directly to array ref because + // first is fat pointer and second is not. + &mut *(slice.as_mut_ptr() as *mut Self) + } +} +unsafe impl Array for [T; N] { crate::if_alloc! { #[inline] fn into_boxed_slice(self) -> alloc::boxed::Box<[Self::Item]> { @@ -341,162 +694,96 @@ unsafe impl Array for [T; 0] { } #[inline] - fn as_slice(&self) -> &[T] { - &[] + fn lift(self, f: F) -> [U; N] + where + F: FnMut(Self::Item) -> U, + { + match self.iter_move().map(f).collect_array() { + Some(ret) => ret, + None => unsafe { + debug_assert!(false); + unreachable_unchecked() + }, + } + } + + #[inline] + fn as_refs(&self) -> [&Self::Item; N] { + self.iter().collect_array().unwrap() + } + + #[inline] + fn as_mut_refs(&mut self) -> [&mut Self::Item; N] { + self.iter_mut().collect_array().unwrap() } #[inline] - fn as_mut_slice(&mut self) -> &mut [T] { - &mut [] + fn iter_move(self) -> core::array::IntoIter { + <_>::into_iter(self) } #[inline] - fn try_unfold(_init: St, _f: F) -> Result + fn try_unfold(init: St, f: F) -> Result where F: FnMut(&mut St) -> Result, { - Ok([]) + init::try_unfold_array(init, f) } #[inline] - fn unfold(_init: St, _f: F) -> Self + fn unfold(init: St, mut f: F) -> Self where F: FnMut(&mut St) -> Self::Item, { - [] + match init::try_unfold_array(init, |st| Ok::<_, Infallible>(f(st))) { + Ok(ret) => ret, + Err(inf) => match inf {}, + } } #[inline] - fn try_from_fn(_f: F) -> Result + fn try_from_fn(mut f: F) -> Result where F: FnMut(usize) -> Result, { - Ok([]) + init::try_unfold_array(0, |i| { + let item = f(*i)?; + *i += 1; + Ok(item) + }) } #[inline] - fn from_fn(_f: F) -> Self + fn from_fn(mut f: F) -> Self where F: FnMut(usize) -> Self::Item, { - [] + let ret = init::try_unfold_array(0, |i| { + let item = f(*i); + *i += 1; + Ok::<_, Infallible>(item) + }); + + match ret { + Ok(ret) => ret, + Err(inf) => match inf {}, + } } #[inline] - fn try_from_iter(_iter: I) -> Option + fn from_iter(iter: I) -> Option where I: IntoIterator, { - Some([]) - } - - #[inline] - fn into_uninit(self) -> Self::Maybe { - [] + let mut iter = iter.into_iter(); + init::try_unfold_array((), |&mut ()| iter.next().ok_or(())).ok() } } -macro_rules! array_impl { - ($e:tt) => { - unsafe impl Array for [T; $e] { - type Item = T; - type Maybe = [MaybeUninit; $e]; - - const SIZE: usize = $e; - - #[inline] - fn as_slice(&self) -> &[T] { &self[..] } - - #[inline] - fn as_mut_slice(&mut self) -> &mut [T] { &mut self[..] } - - #[inline] - #[allow(unused_mut)] - fn try_unfold(mut init: St, mut f: F) -> Result - where - F: FnMut(&mut St) -> Result - { - Ok( - // this expands to - // - `[f(&mut init)?, ..., f(&mut init)?]`, for arrays of sizes 1..=32 - // - `crate::init::unfold_array`, otherwise - block_specialisation!( - $e, - { $crate::util::init::try_unfold_array(init, f)? }, - { f(&mut init)? } - ) - ) - } - - #[inline] - #[allow(unused_mut)] - fn unfold(mut init: St, mut f: F) -> Self - where - F: FnMut(&mut St) -> Self::Item - { - // this expands to - // - `[f(&mut init), ..., f(&mut init)]`, for arrays of sizes 1..=32 - // - `crate::init::unfold_array`, otherwise - block_specialisation!( - $e, - { $crate::util::init::unfold_array(init, f) }, - { f(&mut init) } - ) - } - - #[inline] - #[allow(unused_mut)] - fn try_from_fn(mut f: F) -> Result - where - F: FnMut(usize) -> Result - { - // this expands to - // - `[f(0)?, f(1)?, f(2)?, ..., f($e - 1)?]`, for arrays of sizes 1..=32 - // - `crate::init::array_init_fn`, otherwise - Ok(try_from_fn_specialisation!($e, f)) - } - - - #[inline] - #[allow(unused_mut)] - fn from_fn(mut f: F) -> Self - where - F: FnMut(usize) -> Self::Item - { - // this expands to - // - `[f(0), f(1), f(2), ..., f($e - 1)]`, for arrays of sizes 1..=32 - // - `crate::init::array_init_fn`, otherwise - from_fn_specialisation!($e, f) - } - - #[inline] - fn try_from_iter(iter: I) -> Option - where - I: IntoIterator - { - #[allow(unused_mut)] - let mut iter = iter.into_iter(); - - Some( - // this expands to - // - `[iter.next()?, ..., iter.next()?]`, for arrays of sizes 1..=32 - // - `crate::init::unfold_array`, otherwise - block_specialisation!( - $e, - { $crate::util::init::array_init_iter(iter)? }, - { iter.next()? } - ) - ) - } - - $crate::if_alloc! { - #[inline] - fn into_boxed_slice(self) -> alloc::boxed::Box<[Self::Item]> { - alloc::boxed::Box::new(self) as _ - } - } - } - }; +// This is a separate function to reduce the code size of ref_cast/mut_cast +// functions. +#[cold] +#[inline(never)] +fn size_expectation_failed() -> ! { + panic!("size of `slice` must not be less than size of `Self` to ref cast to success") } - -array_impls!(array_impl); diff --git a/src/continuous.rs b/src/continuous.rs new file mode 100644 index 0000000..b3c2d2b --- /dev/null +++ b/src/continuous.rs @@ -0,0 +1,348 @@ +use core::{mem::MaybeUninit, slice}; + +use crate::{iter::ArrayWindows, Array, SizeError}; + +/// Continuous data structure consisting of [`len`] [`Item`]s. ie an [`array`] +/// or a [`slice`]. +/// +/// [`len`]: Continuous::len +/// [`Item`]: Continuous::Item +/// [`array`]: array +/// [`slice`]: prim@slice +/// +/// This trait mostly consists of shorthand methods those just refer to +/// `self.as_slice().smt()`. +/// +/// ## Safety +/// +/// Implementors of this trait must be layout compatible with an array (slice) +/// and [`Self::Uninit`]. All functions must be pure (ie not have side effects, +/// return the same value for the same output). [`len`] must be identical to +/// `.as_slice().len()` or `.as_mut_slice().len()`. [`as_slice`], +/// [`as_mut_slice`], [`as_ref`] and [`as_mut`] must return the same values +/// (ignoring the reference type). +/// +/// [`Self::Uninit`]: Continuous::Uninit +/// [`as_slice`]: Continuous::as_slice +/// [`as_mut_slice`]: Continuous::as_mut_slice +/// [`as_ref`]: AsRef::as_ref +/// [`as_mut`]: AsMut::as_mut +pub unsafe trait Continuous: AsRef<[Self::Item]> + AsMut<[Self::Item]> { + /// Type of the Items in the array or slice. i.e. + /// ``` + /// # use arraylib::Continuous; fn dummy() where + /// [T; 4]: Continuous, + /// [T]: Continuous + /// # {} + /// ``` + type Item; + + /// Same array or slice but item is wrapped with + /// [`MaybeUninit<_>`](core::mem::MaybeUninit). + /// ``` + /// # use {arraylib::Continuous, core::mem::MaybeUninit}; fn dummy() where + /// [T; 4]: Continuous; 4]>, + /// [T]: Continuous]> + /// # {} + /// ``` + type Uninit: ?Sized + Continuous>; + + /// Extracts a slice containing the entire array or noop for slices. + /// + /// ## Example + /// + /// ``` + /// use arraylib::Continuous; + /// + /// let array = [1, 2, 3]; + /// assert_eq!(array.as_slice()[1..], [2, 3]); + /// + /// let slice = &[1, 2, 3] as &[_]; + /// assert_eq!(array.as_slice()[1..], [2, 3]); + /// ``` + fn as_slice(&self) -> &[Self::Item]; + + /// Extracts a mutable slice containing the entire array or noop for slices. + /// + /// ## Example + /// + /// ``` + /// use arraylib::Continuous; + /// + /// let mut array = [1, 0, 1]; + /// array.as_mut_slice()[1] = 2; + /// assert_eq!(array, [1, 2, 1]); + /// ``` + fn as_mut_slice(&mut self) -> &mut [Self::Item]; + + /// Returns len of the array or slice. + fn len(&self) -> usize; + + /// Returns true if the array or slice has a length of 0. + #[inline] + fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an iterator over refs to the array or slice. + /// + /// # Examples + /// + /// ``` + /// use arraylib::Continuous; + /// + /// let arr = [1, 2, 4]; + /// let mut iterator = arr.iter(); + /// + /// assert_eq!(iterator.next(), Some(&1)); + /// assert_eq!(iterator.next(), Some(&2)); + /// assert_eq!(iterator.next(), Some(&4)); + /// assert_eq!(iterator.next(), None); + /// ``` + #[inline] + fn iter(&self) -> slice::Iter<'_, Self::Item> { + self.as_ref().iter() + } + + /// Returns an iterator that allows modifying each value. + /// + /// # Examples + /// + /// ``` + /// use arraylib::Continuous; + /// + /// let mut arr = [1, 2, 4]; + /// for elem in arr.iter_mut() { + /// *elem += 2; + /// } + /// assert_eq!(arr, [3, 4, 6]); + /// ``` + #[inline] + fn iter_mut(&mut self) -> slice::IterMut<'_, Self::Item> { + self.as_mut().iter_mut() + } + + crate::if_alloc! { + /// Copies `self` into a new `Vec`. + /// + /// ## Examples + /// + /// ``` + /// use arraylib::Continuous; + /// + /// let arr = [1, 2, 3]; + /// assert_eq!(arr.to_vec(), vec![1, 2, 3]) + /// ``` + /// + /// See also: [`[T]::to_vec`](https://doc.rust-lang.org/std/primitive.slice.html#method.to_vec) + #[inline] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn to_vec(&self) -> alloc::vec::Vec + where + Self::Item: Clone, + { + self.as_slice().to_vec() + } + } + + /// Returns an iterator over all continuous windows of type `&[Item; N]`. + /// The windows overlap. If the slice is shorter than size + /// `N`, the iterator returns `None`. + /// + /// ## Note + /// + /// This function is identical to the + /// [`<[T]>::array_windows`][array_windows] (unstable as of writing this). + /// The name is changed to fix collision warning. + /// + /// [array_windows]: https://doc.rust-lang.org/std/primitive.slice.html#method.array_windows + /// + /// ## Examples + /// + /// ``` + /// use arraylib::Continuous; + /// + /// let mut iter = [1, 2, 3, 4].array_windows_(); + /// assert_eq!(iter.next(), Some(&[1, 2])); + /// assert_eq!(iter.next(), Some(&[2, 3])); + /// assert_eq!(iter.next(), Some(&[3, 4])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// In difference with [`<[T]>::windows`][windows], this method returns + /// iterator that returns _arrays_, so you can use array destruction: + /// + /// [windows]: https://doc.rust-lang.org/std/primitive.slice.html#method.windows + /// + /// ``` + /// use arraylib::Continuous; + /// + /// assert_eq!( + /// [1, 2, 3, 4, 5] + /// .array_windows_() + /// .map(|[a, b, c]| a + b + c) + /// .sum::(), + /// 27 + /// ) + /// ``` + /// + /// If the slice is shorter than size: + /// + /// ``` + /// use arraylib::Continuous; + /// + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.array_windows_::<4>(); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// ## Panics + /// + /// Panics if `N` is 0. + #[inline] + fn array_windows_(&self) -> ArrayWindows { + ArrayWindows::new(self.as_ref()) + } + + /// Copy `self` into an owned array. + /// + /// Returns `Err(SizeError { .. })` if lenght of `self` is not equal to `N`. + /// + /// ## Examples + /// + /// ``` + /// use arraylib::Continuous; + /// + /// let slice: &[i32] = &[0, 1, 2, 3, 4]; + /// let array: [i32; 5] = slice.copied().unwrap(); + /// assert_eq!(array, [0, 1, 2, 3, 4]); + /// ``` + /// + /// ``` + /// use arraylib::{Continuous, SizeError}; + /// + /// let slice: &[i32] = &[0, 1, 2, 3, 4]; + /// let result = slice.copied::<2>(); + /// + /// let SizeError { + /// expected, found, .. + /// } = result.unwrap_err(); + /// assert_eq!(expected, 2); + /// assert_eq!(found, 5); + /// ``` + #[inline] + fn copied(&self) -> Result<[Self::Item; N], SizeError> + where + Self::Item: Copy, + { + Array::from_slice(self.as_ref()) + } + + /// Clone `self` into an owned array. + /// + /// Return `Err(SizeError { .. })` if lenght of `self` is not equal to `N`. + /// + /// ## Examples + /// + /// ``` + /// use arraylib::Continuous; + /// use core::ops::Range; + /// + /// // Range is not `Copy` + /// let slice: &[Range] = &[0..1, 1..3, 2..10]; + /// let array: [Range; 3] = slice.cloned().unwrap(); + /// assert_eq!(array, [0..1, 1..3, 2..10]); + /// ``` + /// + /// ``` + /// use arraylib::{Continuous, SizeError}; + /// use core::ops::Range; + /// + /// let slice: &[Range] = &[0..1, 1..3, 2..10]; + /// let result = slice.cloned::<5>(); + /// + /// let SizeError { + /// expected, found, .. + /// } = result.unwrap_err(); + /// assert_eq!(expected, 5); + /// assert_eq!(found, 3); + /// ``` + #[inline] + fn cloned(&self) -> Result<[Self::Item; N], SizeError> + where + Self::Item: Clone, + { + Array::clone_from_slice(self.as_ref()) + } + + /// ## Safety + unsafe fn assume_init_ref(this: &Self::Uninit) -> &Self; + + /// ## Safety + unsafe fn assume_init_mut(this: &mut Self::Uninit) -> &mut Self; +} + +unsafe impl Continuous for [T] { + type Item = T; + type Uninit = [MaybeUninit]; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } + + #[inline] + fn as_mut_slice(&mut self) -> &mut [Self::Item] { + self + } + + #[inline] + fn len(&self) -> usize { + self.len() + } + + #[inline] + unsafe fn assume_init_ref(this: &Self::Uninit) -> &Self { + &*(this as *const _ as *const _) + } + + #[inline] + unsafe fn assume_init_mut(this: &mut Self::Uninit) -> &mut Self { + &mut *(this as *mut _ as *mut _) + } +} + +unsafe impl Continuous for [T; N] { + type Item = T; + type Uninit = [MaybeUninit; N]; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } + + #[inline] + fn as_mut_slice(&mut self) -> &mut [Self::Item] { + self + } + + #[inline] + fn len(&self) -> usize { + N + } + + #[inline] + fn is_empty(&self) -> bool { + N == 0 + } + + #[inline] + unsafe fn assume_init_ref(this: &Self::Uninit) -> &Self { + &*(this as *const _ as *const _) + } + + #[inline] + unsafe fn assume_init_mut(this: &mut Self::Uninit) -> &mut Self { + &mut *(this as *mut _ as *mut _) + } +} diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ext/array_ext.rs b/src/ext/array_ext.rs deleted file mode 100644 index 2b21109..0000000 --- a/src/ext/array_ext.rs +++ /dev/null @@ -1,471 +0,0 @@ -use crate::{ - iter::IterMove, util::transmute::extremely_unsafe_transmute, Array, ArrayWrapper, SizeError, -}; - -/// Extension on arrays that provide additional functions. -pub trait ArrayExt: Array { - /// Creates iterator which moves elements out of array. - /// - /// See also: [IterMove](crate::iter::IterMove) - #[inline] - fn iter_move(self) -> IterMove { - IterMove::new(self) - } - - /// ## Example - /// ``` - /// use arraylib::ArrayExt; - /// - /// let arr: [_; 6] = [1, 2, 3].concat_arr([4, 5, 6]); - /// assert_eq!(arr, [1, 2, 3, 4, 5, 6]) - /// ``` - /// - /// ## Panics - /// - /// Panics if `Self::SIZE` + `A::SIZE` != `R::SIZE`: - /// - /// ```should_panic - /// use arraylib::ArrayExt; - /// - /// let arr: [_; 4] = [1, 2, 3].concat_arr([4, 5, 6]); - /// ``` - #[inline] - fn concat_arr(self, other: A) -> R - where - A: Array, - R: Array, - { - unsafe { - // Because of lack of const generics we need to assert this in runtime :( - // - // It's also possible to add trait like `ArrayConcat { type Output }` but - // this leads to A LOT of impls and SLOW compile times. - assert_eq!(Self::SIZE + A::SIZE, R::SIZE); - - #[repr(C, packed)] - struct Both(Slf, A); - - // ## Safety - // - // We know that all `Self`, `A` and `R` are arrays. - // Also we know that `Self::SIZE + A::SIZE == R::SIZE`, that means that we can - // concat `Self` with `A` and we'll obtain `R`. - // - // Because of fact that all types are arrays (and fact that `Both` is - // `#[repr(C, packed)]`), we know that `Both` is equal to `R`, so we - // can safely transmute one into another. - let both = Both(self, other); - extremely_unsafe_transmute::, R>(both) - } - } - - /// Splits self into 2 arrays - /// - /// ## Example - /// ``` - /// use arraylib::ArrayExt; - /// - /// let arr = [1, 2, 3, 4, 5]; - /// let (head, tail) = arr.split_arr::<[_; 2], [_; 3]>(); - /// - /// assert_eq!(head, [1, 2]); - /// assert_eq!(tail, [3, 4, 5]); - /// ``` - #[inline] - fn split_arr(self) -> (A, B) - where - A: Array, - B: Array, - { - unsafe { - // Because of lack of const generics we need to assert this in runtime :( - // - // It's also possible to add trait like `ArraySplit { ... }` but this - // leads to A LOT of impls and SLOW compile times. - assert_eq!(Self::SIZE, A::SIZE + B::SIZE); - - #[repr(C, packed)] - struct Both(A, B); - - // ## Safety - // - // We know that all `Self`, `A` and `B` are arrays. - // Also we know that `Self::SIZE, A::SIZE + B::SIZE`, that means that we can - // split `Self` into `A` and `B`. - // - // Because of fact that all types are arrays (and fact that `Both` is - // `#[repr(C, packed)]`), we know that `Both` is equal to `R`, so we - // can safely transmute one into another. - let Both(a, b): Both = extremely_unsafe_transmute::>(self); - (a, b) - } - } - - /// Converts `self` into an array. This function will return `Some(_)` if - /// sizes of `Self` and `A` are the same and `None` otherwise. - /// - /// ## Example - /// ``` - /// use arraylib::{Array, ArrayExt}; - /// - /// fn function_optimized_for_8(_: [i32; 8]) { - /// /* ... */ - /// } - /// - /// fn general(array: A) - /// where - /// A: Array, - /// { - /// match array.into_array::<[i32; 8]>() { - /// Ok(array) => function_optimized_for_8(array), - /// Err(array) => { /* here `array` is of type `A` */ }, - /// } - /// } - /// ``` - #[inline] - fn into_array(self) -> Result - where - A: Array, - { - if Self::SIZE == A::SIZE { - // ## Safety - // - // Item types and sizes are same for both `Self` and `A`, so it's the same type. - Ok(unsafe { extremely_unsafe_transmute::(self) }) - } else { - Err(self) - } - } - - crate::if_alloc! { - /// Copies `self` into a new `Vec`. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::{Array, ArrayExt}; - /// - /// fn generic(arr: A) - /// where - /// A: Array, - /// A::Item: Clone, - /// { - /// let x = arr.to_vec(); - /// // Here, `arr` and `x` can be modified independently. - /// } - /// ``` - /// - /// See also: [`[T]::to_vec`](https://doc.rust-lang.org/std/primitive.slice.html#method.to_vec) - #[inline] - #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - fn to_vec(&self) -> alloc::vec::Vec - where - Self::Item: Clone, - { - self.as_slice().to_vec() - } - - /// Converts `self` into a vector without clones. - /// - /// The resulting vector can be converted back into a box via - /// `Vec`'s `into_boxed_slice` method. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::ArrayExt; - /// - /// let s = [10, 40, 30]; - /// let x = s.into_vec(); - /// // `s` cannot be used anymore because it has been converted into `x`. - /// - /// assert_eq!(x, vec![10, 40, 30]); - /// ``` - /// - /// See also: [`[T]::into_vec`](https://doc.rust-lang.org/std/primitive.slice.html#method.into_vec) - #[inline] - #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - fn into_vec(self) -> alloc::vec::Vec { - self.into_boxed_slice().into_vec() - } - } - - /// Create array from slice. Return `Err(())` if `slice.len != Self::SIZE`. - /// - /// ## Examples - /// ``` - /// use arraylib::ArrayExt; - /// - /// let slice = &[1, 2, 3]; - /// let arr = <[i32; 3]>::from_slice(slice); - /// assert_eq!(arr, Ok([1, 2, 3])); - /// ``` - /// - /// ``` - /// # use arraylib::{ArrayExt, SizeError}; - /// let slice = &[1, 2, 3, 4]; - /// let arr = <[i32; 2]>::from_slice(slice); - /// // ^^^^^^ ---- wrong size, slice len = 4, arr len = 2 - /// assert_eq!(arr, Err(SizeError::default())); - /// ``` - #[inline] - fn from_slice(slice: &[Self::Item]) -> Result - where - Self::Item: Copy, - { - if slice.len() == Self::SIZE { - Ok(Self::try_from_iter(slice.iter().copied()).unwrap()) - } else { - Err(SizeError::default()) - } - } - - /// Create array from slice. Return `Err(())` if `slice.len != Self::SIZE`. - /// - /// Same as [`from_slice`](crate::ArrayExt::from_slice), but doesn't require - /// items to be `Copy`, instead only require elements to be `Clone` - /// - /// ## Examples - /// - /// ``` - /// use arraylib::ArrayExt; - /// - /// let slice = &[String::from("hi"), 123.to_string(), String::new()]; - /// let arr = <[String; 3]>::clone_from_slice(slice); - /// assert_eq!( - /// arr, - /// Ok([String::from("hi"), 123.to_string(), String::new()]) - /// ); - /// ``` - #[inline] - fn clone_from_slice(slice: &[Self::Item]) -> Result - where - Self::Item: Clone, - { - if slice.len() == Self::SIZE { - Ok(Self::try_from_iter(slice.iter().cloned()).unwrap()) - } else { - Err(SizeError::default()) - } - } - - /// Wrap `self` into [`ArrayWrapper`](crate::ArrayWrapper) - #[inline] - fn wrap(self) -> ArrayWrapper { - ArrayWrapper::new(self) - } - - /// Safely cast `&[T]` to `&Self` (`[T; N]`) - /// - /// ## Panics - /// - /// Panics if size of `slice` is less than size of `Self`. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::ArrayExt; - /// - /// let vec = vec![1, 0, 2, 14]; - /// assert_eq!(<[i32; 4]>::ref_cast(&vec[..]), &[1, 0, 2, 14]); - /// ``` - /// - /// ```should_panic - /// # use arraylib::ArrayExt; - /// // panics - /// <[i32; 4]>::ref_cast(&[1, 2][..]); - /// ``` - #[inline] - fn ref_cast(slice: &[Self::Item]) -> &Self { - match Self::try_ref_cast(slice) { - Ok(x) => x, - Err(_) => size_expectation_failed(), - } - } - - /// Safely cast `&mut [T]` to `&mut Self` (`[T; N]`) - /// - /// ## Panics - /// - /// Panics if size of `slice` is less than size of `Self`. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::{ArrayExt, SizeError}; - /// - /// let mut vec = vec![1, 0, 2, 14]; - /// assert_eq!(<[i32; 4]>::mut_cast(&mut vec[..]), &mut [1, 0, 2, 14]); - /// ``` - /// - /// ```should_panic - /// # use arraylib::ArrayExt; - /// // panics - /// <[i32; 4]>::mut_cast(&mut [1, 2][..]); - /// ``` - #[inline] - fn mut_cast(slice: &mut [Self::Item]) -> &mut Self { - match Self::try_mut_cast(slice) { - Ok(x) => x, - Err(_) => size_expectation_failed(), - } - } - - /// Safely cast `&[T]` to `&Self` (`[T; N]`) - /// - /// ## Errors - /// - /// If size of `slice` is less than size of `Self`, then an error is - /// returned. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::{ArrayExt, SizeError}; - /// - /// let vec = vec![1, 0, 2, 14]; - /// assert_eq!(<[i32; 4]>::try_ref_cast(&vec[..]), Ok(&[1, 0, 2, 14])); - /// assert_eq!(<[i32; 4]>::try_ref_cast(&vec[1..=2]), Err(&[0, 2][..])); - /// ``` - #[inline] - fn try_ref_cast(slice: &[Self::Item]) -> Result<&Self, &[Self::Item]> { - unsafe { - if slice.len() >= Self::SIZE { - Ok(Self::ref_cast_unchecked(slice)) - } else { - Err(slice) - } - } - } - - /// Safely cast `&mut [T]` to `&mut Self` (`[T; N]`) - /// - /// ## Errors - /// - /// If size of `slice` is less than size of `Self`, then an error is - /// returned. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::{ArrayExt, SizeError}; - /// - /// let mut vec = vec![1, 0, 2, 14]; - /// assert_eq!( - /// <[i32; 4]>::try_mut_cast(&mut vec[..]), - /// Ok(&mut [1, 0, 2, 14]) - /// ); - /// assert_eq!( - /// <[i32; 4]>::try_mut_cast(&mut vec[1..=2]), - /// Err(&mut [0, 2][..]) - /// ); - /// ``` - #[inline] - fn try_mut_cast(slice: &mut [Self::Item]) -> Result<&mut Self, &mut [Self::Item]> { - unsafe { - if slice.len() >= Self::SIZE { - Ok(Self::mut_cast_unchecked(slice)) - } else { - Err(slice) - } - } - } - - /// Unsafety cast `&[T]` to `&Self` (`[T; N]`) - /// - /// ## Safety - /// - /// To safely call this function you need to ensure that size of slice is - /// not less than the size of array: `slice.len() >= Self::SIZE` - /// - /// ## Examples - /// - /// ok usage: - /// ``` - /// use arraylib::ArrayExt; - /// - /// let vec = vec![1, 0, 2, 14]; - /// - /// let _: &[i32; 4] = unsafe { - /// // Safe because we know that size of `vec` is equal 4 - /// <[i32; 4]>::ref_cast_unchecked(&vec[..]) - /// }; - /// ``` - /// **wrong** (UB) usage: - /// ```no_run - /// use arraylib::ArrayExt; - /// - /// let vec = vec![1, 0, 2, 14]; - /// - /// let _: &[i32; 4] = unsafe { - /// // size of slice borrowed from `vec` is not equal to 4 so this is UB - /// <[i32; 4]>::ref_cast_unchecked(&vec[1..]) - /// }; - /// ``` - #[inline] - unsafe fn ref_cast_unchecked(slice: &[Self::Item]) -> &Self { - // ## (Un)Safety - // - // Slice and array of the same size must have the same ABI, so we can safely get - // `&[T; N]` from `&[A::Item]` **if `slice.len()` >= N**. Here it is not - // checked, so this method is unsafe. - // - // We can't transmute slice ref directly to array ref because - // first is fat pointer and second is not. - &*(slice.as_ptr() as *const Self) - } - - /// Unsafety cast `&mut [T]` to `&mut Self` (`[T; N]`) - /// - /// ## Safety - /// - /// To safely call this function you need to ensure that size of slice is - /// not less than the size of array: `slice.len() >= Self::SIZE` - /// - /// ## Examples - /// - /// ok usage: - /// ``` - /// use arraylib::ArrayExt; - /// - /// let mut vec = vec![1, 0, 2, 14]; - /// - /// let _: &[i32; 4] = unsafe { - /// // Safe because we know that size of `vec` is equal 4 - /// <[i32; 4]>::ref_cast_unchecked(&mut vec[..]) - /// }; - /// ``` - /// **wrong** (UB) usage: - /// ```no_run - /// use arraylib::ArrayExt; - /// - /// let mut vec = vec![1, 0, 2, 14]; - /// - /// let _: &[i32; 4] = unsafe { - /// // size of slice borrowed from `vec` is not equal to 4 so this is UB - /// <[i32; 4]>::ref_cast_unchecked(&mut vec[1..]) - /// }; - /// ``` - #[inline] - unsafe fn mut_cast_unchecked(slice: &mut [Self::Item]) -> &mut Self { - // ## (Un)Safety - // - // Slice and array of the same size must have the same ABI, so we can safely get - // `&mut [T; N]` from `&mut [A::Item]` **if `slice.len()` >= N**. Here it is not - // checked, so this method is unsafe. - // - // We can't transmute slice ref directly to array ref because - // first is fat pointer and second is not. - &mut *(slice.as_mut_ptr() as *mut Self) - } -} - -impl ArrayExt for A where A: Array {} - -// This is a separate function to reduce the code size of ref_cast/mut_cast -// functions. -#[cold] -#[inline(never)] -fn size_expectation_failed() -> ! { - panic!("size of `slice` must not be less than size of `Self` to ref cast to success") -} diff --git a/src/ext/shorthand.rs b/src/ext/shorthand.rs deleted file mode 100644 index 81ca1aa..0000000 --- a/src/ext/shorthand.rs +++ /dev/null @@ -1,130 +0,0 @@ -use core::{mem, slice, slice::SliceIndex}; - -use crate::Array; - -/// Shorthand methods those just refer to `self.as_slice().smt()` -pub trait ArrayShorthand: Array { - /// Returns a reference to the value corresponding to the supplied index. - /// - /// ## Example - /// ``` - /// use arraylib::{Array, ArrayShorthand}; - /// - /// fn slice(arr: &A) -> (&A::Item, &[A::Item]) - /// where - /// A: Array, - /// { - /// (arr.index(0), arr.index(1..)) - /// } - /// - /// assert_eq!(slice(&[1, 2, 3]), (&1, &[2, 3][..])) - /// ``` - /// - /// See also: [`index_mut`](ArrayShorthand::index_mut) - #[inline] - fn index(&self, idx: Idx) -> &Idx::Output - where - Idx: SliceIndex<[Self::Item]>, - { - &self.as_slice()[idx] - } - - /// Returns a unique reference to the value corresponding to the supplied - /// index. - /// - /// ## Example - /// ``` - /// use arraylib::{Array, ArrayShorthand}; - /// - /// fn slice(arr: &mut A) -> &mut [A::Item] - /// where - /// A: Array, - /// { - /// arr.index_mut(1..) - /// } - /// - /// assert_eq!(slice(&mut [1, 2, 3]), &mut [2, 3]) - /// ``` - /// - /// See also: [`index`](ArrayShorthand::index) - #[inline] - fn index_mut(&mut self, idx: Idx) -> &mut Idx::Output - where - Idx: SliceIndex<[Self::Item]>, - { - &mut self.as_mut_slice()[idx] - } - - /// Replace element of the array - /// - /// ## Example - /// ``` - /// use arraylib::ArrayShorthand; - /// - /// let mut arr = ["hello", "", "world"]; - /// assert_eq!(arr.replace(1, ", "), ""); - /// assert_eq!(arr, ["hello", ", ", "world"]) - /// ``` - #[inline] - fn replace(&mut self, idx: usize, item: Self::Item) -> Self::Item { - mem::replace(self.index_mut(idx), item) - } - - /// Take element of the array, replacing it with default - /// - /// ## Example - /// ``` - /// use arraylib::ArrayShorthand; - /// - /// let mut arr = [String::from("hello, "), String::from("world")]; - /// assert_eq!(arr.take(1), "world"); - /// assert_eq!(arr, ["hello, ", ""]) - /// ``` - #[inline] - fn take(&mut self, idx: usize) -> Self::Item - where - Self::Item: Default, - { - self.replace(idx, <_>::default()) - } - - /// Returns an iterator over refs to the array. - /// - /// # Examples - /// - /// ``` - /// use arraylib::ArrayShorthand; - /// - /// let arr = [1, 2, 4]; - /// let mut iterator = arr.iter(); - /// - /// assert_eq!(iterator.next(), Some(&1)); - /// assert_eq!(iterator.next(), Some(&2)); - /// assert_eq!(iterator.next(), Some(&4)); - /// assert_eq!(iterator.next(), None); - /// ``` - #[inline] - fn iter(&self) -> slice::Iter<'_, Self::Item> { - self.as_slice().iter() - } - - /// Returns an iterator that allows modifying each value. - /// - /// # Examples - /// - /// ``` - /// use arraylib::ArrayShorthand; - /// - /// let mut arr = [1, 2, 4]; - /// for elem in arr.iter_mut() { - /// *elem += 2; - /// } - /// assert_eq!(arr, [3, 4, 6]); - /// ``` - #[inline] - fn iter_mut(&mut self) -> slice::IterMut<'_, Self::Item> { - self.as_mut_slice().iter_mut() - } -} - -impl ArrayShorthand for A where A: Array {} diff --git a/src/ext/slice_ext.rs b/src/ext/slice_ext.rs deleted file mode 100644 index f493955..0000000 --- a/src/ext/slice_ext.rs +++ /dev/null @@ -1,220 +0,0 @@ -use core::mem::MaybeUninit; - -use crate::{iter::ArrayWindows, Array, ArrayExt, SizeError}; - -/// Extension for [`slice`] -/// -/// [`slice`]: core::slice -pub trait Slice { - /// Item of the slice, i.e. - /// ``` - /// # use arraylib::Slice; fn dummy() where - /// [T]: Slice - /// # {} - /// ``` - type Item; - - /// Copy `self` into an owned array. - /// Return `Err(SizeError)` if len of `self` is not equal to `A::SIZE`. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::Slice; - /// - /// let slice: &[i32] = &[0, 1, 2, 3, 4]; - /// let array: [i32; 5] = slice.copied().unwrap(); - /// assert_eq!(array, [0, 1, 2, 3, 4]); - /// ``` - /// - /// ``` - /// use arraylib::{SizeError, Slice}; - /// - /// let slice: &[i32] = &[0, 1, 2, 3, 4]; - /// let result = slice.copied::<[i32; 2]>(); - /// assert_eq!(result, Err(SizeError::default())); - /// ``` - fn copied(&self) -> Result - where - A: Array, - A::Item: Copy; - - /// Clone `self` into an owned array. - /// Return `Err(SizeError)` if len of `self` is not equal to `A::SIZE`. - /// - /// ## Examples - /// - /// ``` - /// use arraylib::Slice; - /// use core::ops::Range; - /// - /// // Range is not `Copy` - /// let slice: &[Range] = &[0..1, 1..3, 2..10]; - /// let array: [Range; 3] = slice.cloned().unwrap(); - /// assert_eq!(array, [0..1, 1..3, 2..10]); - /// ``` - /// - /// ``` - /// use arraylib::{SizeError, Slice}; - /// use core::ops::Range; - /// - /// let slice: &[Range] = &[0..1, 1..3, 2..10]; - /// let result = slice.cloned::<[Range; 5]>(); - /// assert_eq!(result, Err(SizeError::default())); - /// ``` - fn cloned(&self) -> Result - where - A: Array, - A::Item: Clone; - - /// Returns an iterator over all contiguous windows of type `A` (length - /// `A::SIZE`). The windows overlap. If the slice is shorter than size - /// (`A::SIZE`), the iterator returns `None`. - /// - /// ## Panics - /// - /// Panics if `A::SIZE` is 0 (`A = [T; 0]`). - /// - /// ## Examples - /// - /// ``` - /// use arraylib::Slice; - /// - /// let mut iter = [1, 2, 3, 4].array_windows::<[_; 2]>(); - /// assert_eq!(iter.next(), Some(&[1, 2])); - /// assert_eq!(iter.next(), Some(&[2, 3])); - /// assert_eq!(iter.next(), Some(&[3, 4])); - /// assert_eq!(iter.next(), None); - /// ``` - /// - /// In difference with [`<[T]>::windows`], this method returns iterator that - /// returns _arrays_, so you can use array destruction: - /// - /// [`<[T]>::windows`]: https://doc.rust-lang.org/std/primitive.slice.html#method.windows - /// - /// ``` - /// use arraylib::Slice; - /// - /// assert_eq!( - /// [1, 2, 3, 4, 5] - /// .array_windows::<[u32; 3]>() - /// .map(|[a, b, c]| a + b + c) - /// .sum::(), - /// 27 - /// ) - /// ``` - /// - /// If the slice is shorter than size: - /// - /// ``` - /// use arraylib::Slice; - /// - /// let slice = ['f', 'o', 'o']; - /// let mut iter = slice.array_windows::<[_; 4]>(); - /// assert!(iter.next().is_none()); - /// ``` - fn array_windows(&self) -> ArrayWindows - where - A: Array; -} - -/// Extension for maybe uninitialized slices (`[MaybeUninit<_>]`) -pub trait MaybeUninitSlice: - Slice::InitItem>> -{ - /// Initialized item i.e. - /// ``` - /// # use std::mem::MaybeUninit; - /// # use arraylib::MaybeUninitSlice; - /// # fn dummy() - /// # where - /// [MaybeUninit]: MaybeUninitSlice - /// # {} - /// ``` - type InitItem; - - /// Assume that all items of self are initialized - /// - /// ## Safety - /// - /// It is up to the caller to guarantee that all elements of the array are - /// really in an initialized state. Calling this when the content is not - /// yet fully initialized causes immediate undefined behavior. The - /// [`MaybeUninit's` type-level documentation][inv] contains - /// more information about this initialization invariant. - /// - /// See also [`MaybeUninit::assume_init`] documentation. - /// - /// [inv]: core::mem#initialization-invariant - /// [`MaybeUninit::assume_init`]: core::mem::MaybeUninit::assume_init - unsafe fn assume_init(&self) -> &[Self::InitItem]; - - /// Assume that all items of self are initialized - /// - /// ## Safety - /// - /// It is up to the caller to guarantee that all elements of the array are - /// really in an initialized state. Calling this when the content is not - /// yet fully initialized causes immediate undefined behavior. The - /// [`MaybeUninit's` type-level documentation][inv] contains - /// more information about this initialization invariant. - /// - /// See also [`MaybeUninit::assume_init`] documentation. - /// - /// [inv]: core::mem#initialization-invariant - /// [`MaybeUninit::assume_init`]: core::mem::MaybeUninit::assume_init - unsafe fn assume_init_mut(&mut self) -> &mut [Self::InitItem]; -} - -impl Slice for [T] { - type Item = T; - - #[inline] - fn copied(&self) -> Result - where - A: Array, - A::Item: Copy, - { - A::from_slice(self) - } - - #[inline] - fn cloned(&self) -> Result - where - A: Array, - A::Item: Clone, - { - A::clone_from_slice(self) - } - - #[inline] - fn array_windows(&self) -> ArrayWindows - where - A: Array, - { - ArrayWindows::new(self) - } -} - -impl MaybeUninitSlice for [MaybeUninit] { - type InitItem = T; - - #[inline] - unsafe fn assume_init(&self) -> &[Self::InitItem] { - // # Unsafety - // - // Behavior is undefined if any of `MaybeUninit`s in `self` is in the - // `uninit` state - //ref_cast::<[MaybeUninit], [T]>(self) - &*(self as *const [MaybeUninit] as *const [T]) - } - - #[inline] - unsafe fn assume_init_mut(&mut self) -> &mut [Self::InitItem] { - // # Unsafety - // - // Behavior is undefined if any of `MaybeUninit`s in `self` is in the - // `uninit` state - &mut *(self as *mut [MaybeUninit] as *mut [T]) - } -} diff --git a/src/iter/chunks.rs b/src/iter/chunks.rs index b2984f8..480b111 100644 --- a/src/iter/chunks.rs +++ b/src/iter/chunks.rs @@ -6,13 +6,15 @@ use crate::Array; /// Created by [`IteratorExt::array_chunks`][method] method, /// /// [method]: crate::iter::IteratorExt::array_chunks -pub struct ArrayChunks { +pub struct ArrayChunks { iter: I, - marker: PhantomData, + marker: PhantomData<[T; N]>, } -impl ArrayChunks { +impl ArrayChunks { pub(crate) fn new(iter: I) -> Self { + assert!(N > 0, "Size of chunks must be greater that zero"); + Self { iter, marker: PhantomData, @@ -20,90 +22,68 @@ impl ArrayChunks { } } -impl Iterator for ArrayChunks +impl Iterator for ArrayChunks where - I: Iterator, - A: Array, + I: Iterator, { - type Item = A; + type Item = [T; N]; #[inline] fn next(&mut self) -> Option { - A::try_from_iter(self.iter.by_ref()) + Array::from_iter(self.iter.by_ref()) } #[inline] fn size_hint(&self) -> (usize, Option) { let (down, upper) = self.iter.size_hint(); - (down / A::SIZE, upper.map(|it| it / A::SIZE)) - } -} - -impl DoubleEndedIterator for ArrayChunks -where - I: DoubleEndedIterator, - A: Array, -{ - #[inline] - fn next_back(&mut self) -> Option { - A::try_from_iter(self.iter.by_ref().rev()) + (down / N, upper.map(|it| it / N)) } } -impl ExactSizeIterator for ArrayChunks +impl ExactSizeIterator for ArrayChunks where - I: ExactSizeIterator, - A: Array, + I: ExactSizeIterator, { #[inline] fn len(&self) -> usize { - self.iter.len() / A::SIZE + self.iter.len() / N } #[inline] #[cfg(feature = "nightly")] fn is_empty(&self) -> bool { - self.iter.len() < A::SIZE + self.iter.len() < N } } -impl fmt::Debug for ArrayChunks { +impl fmt::Debug for ArrayChunks { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Chunks") + f.debug_struct("ArrayChunks") .field("iter", &self.iter) - .field("chunk_len", &A::SIZE) + .field("chunk_len", &N) .finish() } } #[cfg(test)] mod tests { - use crate::{iter::IteratorExt, ArrayExt}; + use crate::{iter::IteratorExt, Array}; #[test] fn basic_usage() { - let mut iter = [0, 1, 2, 3, 4].iter_move().array_chunks::<[_; 2]>(); + let mut iter = [0, 1, 2, 3, 4].iter_move().array_chunks::<2>(); assert_eq!(iter.next(), Some([0, 1])); assert_eq!(iter.next(), Some([2, 3])); assert_eq!(iter.next(), None); } - #[test] - fn back() { - let mut iter = [0, 1, 2, 3, 4].iter_move().array_chunks::<[_; 2]>().rev(); - - assert_eq!(iter.next(), Some([4, 3])); - assert_eq!(iter.next(), Some([2, 1])); - assert_eq!(iter.next(), None); - } - #[test] fn len() { macro_rules! assert_len { (size: $array_size:literal, chunk: $chunk_size:literal, expect: $expected:literal) => { - let array = [0; $array_size].iter_move().array_chunks::<[_; $chunk_size]>(); + let array = [0; $array_size].iter_move().array_chunks::<$chunk_size>(); assert_eq!(array.len(), $expected); }; ( diff --git a/src/iter/ext.rs b/src/iter/ext.rs index e0f1fc0..73b4efc 100644 --- a/src/iter/ext.rs +++ b/src/iter/ext.rs @@ -13,24 +13,13 @@ pub trait IteratorExt: Iterator { /// use arraylib::iter::IteratorExt; /// /// let vec = vec![0, 1, 2, 3, 4]; - /// let mut chunks = vec.into_iter().array_chunks::<[_; 2]>(); + /// let mut chunks = vec.into_iter().array_chunks::<2>(); /// /// assert_eq!(chunks.next(), Some([0, 1])); /// assert_eq!(chunks.next(), Some([2, 3])); /// assert_eq!(chunks.next(), None); /// ``` /// - /// ``` - /// use arraylib::iter::IteratorExt; - /// - /// let vec = vec![0, 1, 2, 3, 4]; - /// let mut chunks = vec.into_iter().array_chunks::<[_; 2]>(); - /// - /// assert_eq!(chunks.next_back(), Some([4, 3])); - /// assert_eq!(chunks.next_back(), Some([2, 1])); - /// assert_eq!(chunks.next_back(), None); - /// ``` - /// /// ## Panics /// /// If `A::SIZE == 0` @@ -39,19 +28,17 @@ pub trait IteratorExt: Iterator { /// use arraylib::iter::IteratorExt; /// /// let vec = vec![0, 1, 2, 3, 4]; - /// let _chunks = vec.into_iter().array_chunks::<[_; 0]>(); + /// let _chunks = vec.into_iter().array_chunks::<0>(); /// ``` /// /// See also [`slice::chunks`][chunks] /// /// [chunks]: ../../core/primitive.slice.html#method.chunks #[inline] - fn array_chunks(self) -> ArrayChunks + fn array_chunks(self) -> ArrayChunks where Self: Sized, - A: Array, { - assert!(A::SIZE > 0, "Size of chunks must be greater that zero"); ArrayChunks::new(self) } @@ -70,7 +57,7 @@ pub trait IteratorExt: Iterator { /// use arraylib::iter::IteratorExt; /// /// let a = [1, 2, 3]; - /// let doubled: [_; 3] = a.iter().map(|&x| x * 2).collect_array(); + /// let doubled: [_; 3] = a.iter().map(|&x| x * 2).collect_array().unwrap(); /// /// assert_eq!([2, 4, 6], doubled); /// ``` @@ -82,48 +69,14 @@ pub trait IteratorExt: Iterator { /// ```should_panic /// use arraylib::iter::IteratorExt; /// - /// [1, 2, 3].iter().collect_array::<[_; 16]>(); - /// ``` - #[inline] - fn collect_array(self) -> A - where - Self: Sized, - A: Array, - { - A::from_iter(self) - } - - /// Transforms an iterator into an array. - /// - /// `collect_array()` can take anything iterable, and turn it into an array - /// of relevant size. - /// - /// This method returns `None` if there are not enough elements to fill the - /// array. - /// - /// See also: [`Iterator::collect`](core::iter::Iterator::collect) - /// - /// ## Example - /// - /// Basic usage: - /// - /// ``` - /// use arraylib::iter::IteratorExt; - /// - /// let a = [1, 2, 3]; - /// let doubled = a.iter().map(|&x| x * 2).try_collect_array(); - /// - /// assert_eq!(doubled, Some([2, 4, 6])); - /// - /// assert_eq!([1, 2, 3].iter().try_collect_array::<[_; 16]>(), None) + /// [1, 2, 3].iter().collect_array::<16>().unwrap(); /// ``` #[inline] - fn try_collect_array(self) -> Option + fn collect_array(self) -> Option<[Self::Item; N]> where Self: Sized, - A: Array, { - A::try_from_iter(self) + Array::from_iter(self) } } diff --git a/src/iter/iter_move.rs b/src/iter/iter_move.rs deleted file mode 100644 index d4de1dc..0000000 --- a/src/iter/iter_move.rs +++ /dev/null @@ -1,356 +0,0 @@ -use core::{fmt, iter::FusedIterator, mem::MaybeUninit, ops::Range}; - -use crate::{Array, ArrayShorthand, MaybeUninitSlice}; - -/// Iterator that moves values out of an array. -/// -/// The implementation is very similar to [`std::vec::IntoIter`], however -/// `ArrayIterMove` stores elements on stack and uses indexes instead of -/// pointers. -/// -/// ## Examples -/// ``` -/// # use arraylib::iter::IterMove; -/// let arr = [1, 2, 3]; -/// let mut iter = IterMove::new(arr); -/// assert_eq!(iter.next(), Some(1)); -/// assert_eq!(iter.next(), Some(2)); -/// assert_eq!(iter.next(), Some(3)); -/// assert_eq!(iter.next(), None); -/// ``` -/// It's also possible to constract iter using [`ArrayExt::iter_move`]: -/// ``` -/// use arraylib::ArrayExt; -/// -/// let mut expected = 1; -/// for i in [1, 2, 4, 8, 16, 32, 64, 128].iter_move() { -/// assert_eq!(i, expected); -/// expected *= 2; -/// } -/// ``` -/// This iterator **moves** values out of an array, so it works with `!Copy` -/// types: -/// ``` -/// use arraylib::iter::IterMove; -/// -/// let array = [String::from("hello"), String::from("Tere")]; -/// let mut iter = IterMove::new(array); -/// -/// let string: String = iter.next().unwrap(); -/// assert_eq!(string, "hello"); -/// -/// let string: String = iter.next().unwrap(); -/// assert_eq!(string, "Tere"); -/// ``` -/// -/// ## Implementation details -/// -/// Internally `IterMove` represented by `Range` and -/// `[MaybeUninit; N]` (`MaybeUninit` is needed to take out elements from an -/// array without copying and `UB`). -/// -/// The range represents "alive" part of the array, so all elements of -/// `inner[alive]` are initialized. -/// -/// Diagram of `IterMove<[u32; 8]>` after consuming 3 elements with [`next`] and -/// 2 with [`next_back`]: -/// ```text -/// _____.*------ `alive` -/// / \ -/// inner: [ ~, ~, ~, 1, 2, 3, ~, ~ ] -/// \_____/ \_____/ \__/ -/// | | `---- elements consumed with `next_back` -/// | | (in uninitialized state) -/// | `---- valid elements in initialized state -/// `---- elements consumed with `next` (in uninitialized state) -/// ``` -/// -/// [`std::vec::IntoIter`]: https://doc.rust-lang.org/std/vec/struct.IntoIter.html -/// [`ArrayExt::iter_move`]: crate::ArrayExt::iter_move -/// [`next`]: core::iter::Iterator::next -/// [`next_back`]: core::iter::DoubleEndedIterator::next_back -pub struct IterMove { - // Alive part of the inner array. - // `inner[alive]` must be initialized. - alive: Range, - inner: A::Maybe, -} - -impl IterMove -where - A: Array, -{ - /// Crate new moving iterator from an array - #[inline] - pub fn new(array: A) -> Self { - Self { - alive: 0..A::SIZE, - inner: array.into_uninit(), - } - } - - /// Returns the remaining items of this iterator as a slice. - /// - /// # Examples - /// - /// ``` - /// # use arraylib::ArrayExt; - /// let arr = ['a', 'b', 'c']; - /// - /// let mut iter_move = arr.iter_move(); - /// assert_eq!(iter_move.as_slice(), &['a', 'b', 'c']); - /// - /// let _ = iter_move.next().unwrap(); - /// assert_eq!(iter_move.as_slice(), &['b', 'c']); - /// ``` - #[inline] - pub fn as_slice(&self) -> &[A::Item] { - unsafe { - let slice: &[MaybeUninit] = self.inner.index(self.alive.clone()); - // ## Safety - // - // All elements of inner[alive] are guaranteed to be initialized - slice.assume_init() - } - } - - /// Returns the remaining items of this iterator as a mutable slice. - /// - /// # Examples - /// - /// ``` - /// # use arraylib::ArrayExt; - /// let arr = ['a', 'b', 'c']; - /// - /// let mut iter_move = arr.iter_move(); - /// let _ = iter_move.next().unwrap(); - /// - /// assert_eq!(iter_move.as_mut_slice(), &mut ['b', 'c']); - /// iter_move.as_mut_slice()[0] = 'x'; - /// - /// assert_eq!(iter_move.next().unwrap(), 'x'); - /// assert_eq!(iter_move.next().unwrap(), 'c'); - /// ``` - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [A::Item] { - unsafe { - let slice: &mut [MaybeUninit] = self.inner.index_mut(self.alive.clone()); - // ## Safety - // - // All elements of inner[alive] are guaranteed to be initialized - slice.assume_init_mut() - } - } -} - -impl Iterator for IterMove -where - A: Array, -{ - type Item = A::Item; - - #[inline] - fn next(&mut self) -> Option { - unsafe { - // return if there are no more elements - let idx = self.alive.next()?; - - // ## Safety - // - // `IterMove` guarantees that `inner[alive]`, `idx` is taken from `alive` so - // `inner[idx]` is initialized at the moment, but shouldn't in the future. - let result: A::Item = self.inner.replace(idx, MaybeUninit::uninit()).assume_init(); - - Some(result) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let exact = self.alive.len(); - (exact, Some(exact)) - } - - #[inline] - fn count(self) -> usize { - self.alive.len() - } -} - -impl DoubleEndedIterator for IterMove -where - A: Array, -{ - #[inline] - fn next_back(&mut self) -> Option { - unsafe { - // return if there are no more elements - let idx = self.alive.next_back()?; - - // ## Safety - // - // `IterMove` guarantees that `inner[alive]`, `idx` is taken from `alive` so - // `inner[idx]` is initialized at the moment, but shouldn't in the future. - let result: A::Item = self.inner.replace(idx, MaybeUninit::uninit()).assume_init(); - - Some(result) - } - } -} - -impl ExactSizeIterator for IterMove -where - A: Array, -{ - #[inline] - fn len(&self) -> usize { - self.alive.len() - } - - #[inline] - #[cfg(feature = "nightly")] - fn is_empty(&self) -> bool { - ExactSizeIterator::is_empty(&self.alive) - } -} - -impl FusedIterator for IterMove where A: Array {} - -#[cfg(feature = "nightly")] -unsafe impl core::iter::TrustedLen for IterMove where A: Array {} - -impl Clone for IterMove -where - A: Array, - A::Item: Clone, -{ - #[inline] - fn clone(&self) -> Self { - let inner = { - // Create an uninitialized array of `MaybeUninit`. The `assume_init` is - // safe because the type we are claiming to have initialized here is a - // bunch of `MaybeUninit`s, which do not require initialization. - let mut array: A::Maybe = A::uninit(); - - for i in self.alive.clone() { - let cloned = unsafe { - // ## Safety - // - // This deref is safe because we know that elements - // of `inner[alive]` are initialized - (&*self.inner.index(i).as_ptr()).clone() - }; - *array.index_mut(i) = MaybeUninit::new(cloned); - } - - array - }; - - Self { - alive: self.alive.clone(), - inner, - } - } -} - -impl fmt::Debug for IterMove -where - A: Array, - A::Item: fmt::Debug, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("IterMove").field(&self.as_slice()).finish() - } -} - -impl Drop for IterMove -where - A: Array, -{ - #[inline] - fn drop(&mut self) { - for _ in self { /* drop all remaining elements */ } - } -} - -#[cfg(test)] -mod tests { - use core::{convert::identity, iter}; - - use crate::{iter::IterMove, Array}; - - #[test] - fn empty() { - let arr: [String; 0] = []; - let mut iter = IterMove::new(arr); - - assert_eq!(iter.next(), None); - } - - #[test] - fn test() { - let arr = <[usize; 5]>::from_fn(identity); - let iter = IterMove::new(arr); - - assert!(iter.eq(vec![0, 1, 2, 3, 4])); - } - - #[test] - fn len() { - let arr = <[usize; 5]>::from_fn(identity); - let mut iter = IterMove::new(arr); - - assert_eq!(iter.len(), 5); - - iter.next(); - assert_eq!(iter.len(), 4); - - for _ in iter.by_ref() {} - assert_eq!(iter.len(), 0); - } - - #[test] - fn clone() { - let arr = <[usize; 5]>::from_fn(identity); - let mut iter = IterMove::new(arr); - - assert!(iter.clone().eq(vec![0, 1, 2, 3, 4])); - - iter.next(); - iter.next_back(); - assert!(iter.clone().eq(vec![1, 2, 3])); - - for _ in iter.by_ref() {} - assert!(iter.eq(iter::empty())); - } - - #[test] - fn as_slice() { - let arr = <[usize; 5]>::from_fn(identity); - let mut iter = IterMove::new(arr); - - assert_eq!(iter.as_slice(), &[0, 1, 2, 3, 4]); - assert_eq!(iter.as_mut_slice(), &mut [0, 1, 2, 3, 4]); - - iter.next(); - assert_eq!(iter.as_slice(), &[1, 2, 3, 4]); - assert_eq!(iter.as_mut_slice(), &mut [1, 2, 3, 4]); - - iter.next_back(); - assert_eq!(iter.as_slice(), &[1, 2, 3]); - assert_eq!(iter.as_mut_slice(), &mut [1, 2, 3]); - - for _ in iter.by_ref() {} - assert_eq!(iter.as_slice(), &[]); - assert_eq!(iter.as_mut_slice(), &mut []); - } - - #[test] - fn back() { - let arr = <[usize; 5]>::from_fn(identity); - let iter = IterMove::new(arr).rev(); - - assert!(iter.eq(vec![4, 3, 2, 1, 0])); - } -} diff --git a/src/iter/windows.rs b/src/iter/windows.rs index ff40f08..fc80db9 100644 --- a/src/iter/windows.rs +++ b/src/iter/windows.rs @@ -1,6 +1,6 @@ use core::fmt; -use crate::{Array, ArrayExt}; +use crate::Array; // TODO: check that panicking refcast/index optimizes in a good way @@ -9,32 +9,26 @@ use crate::{Array, ArrayExt}; /// This struct is created by the [`array_windows`] method on [slices]. /// See it's documentation for more. /// -/// [`array_windows`]: crate::Slice::array_windows +/// [`array_windows`]: crate::Continuous::array_windows_ /// [slices]: https://doc.rust-lang.org/std/primitive.slice.html -pub struct ArrayWindows<'a, A: Array> { - slice: &'a [A::Item], +pub struct ArrayWindows<'a, T, const N: usize> { + slice: &'a [T], } -impl<'a, A> ArrayWindows<'a, A> -where - A: Array, -{ - pub(crate) fn new(slice: &'a [A::Item]) -> Self { - assert!(A::SIZE > 0); +impl<'a, T, const N: usize> ArrayWindows<'a, T, N> { + pub(crate) fn new(slice: &'a [T]) -> Self { + assert!(N > 0); Self { slice } } } -impl<'a, A> Iterator for ArrayWindows<'a, A> -where - A: Array + 'a, -{ - type Item = &'a A; +impl<'a, T: 'a, const N: usize> Iterator for ArrayWindows<'a, T, N> { + type Item = &'a [T; N]; #[inline] fn next(&mut self) -> Option { - if self.slice.len() >= A::SIZE { - let r = A::ref_cast(&self.slice[..A::SIZE]); + if self.slice.len() >= N { + let r = Array::ref_cast(&self.slice[..N]); self.slice = &self.slice[1..]; Some(r) } else { @@ -54,8 +48,8 @@ where #[inline] fn last(self) -> Option { - if self.slice.len() > A::SIZE { - Some(A::ref_cast(&self.slice[self.slice.len() - A::SIZE..])) + if self.slice.len() > N { + Some(Array::ref_cast(&self.slice[self.slice.len() - N..])) } else { None } @@ -63,26 +57,23 @@ where #[inline] fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = A::SIZE.overflowing_add(n); + let (end, overflow) = N.overflowing_add(n); if end > self.slice.len() || overflow { self.slice = &[]; None } else { - let nth = A::ref_cast(&self.slice[n..end]); + let nth = Array::ref_cast(&self.slice[n..end]); self.slice = &self.slice[n + 1..]; Some(nth) } } } -impl<'a, A> DoubleEndedIterator for ArrayWindows<'a, A> -where - A: Array + 'a, -{ +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> { #[inline] fn next_back(&mut self) -> Option { - if self.slice.len() >= A::SIZE { - let r = A::ref_cast(&self.slice[self.slice.len() - A::SIZE..]); + if self.slice.len() >= N { + let r = Array::ref_cast(&self.slice[self.slice.len() - N..]); self.slice = &self.slice[..self.slice.len() - 1]; Some(r) } else { @@ -93,54 +84,50 @@ where #[inline] fn nth_back(&mut self, n: usize) -> Option { let (end, overflow) = self.slice.len().overflowing_sub(n); - if end < A::SIZE || overflow { + if end < N || overflow { self.slice = &[]; None } else { - let ret = A::ref_cast(&self.slice[end - A::SIZE..end]); + let ret = Array::ref_cast(&self.slice[end - N..end]); self.slice = &self.slice[..end - 1]; Some(ret) } } } -impl<'a, A> ExactSizeIterator for ArrayWindows<'a, A> -where - A: Array + 'a, -{ +impl<'a, T, const N: usize> ExactSizeIterator for ArrayWindows<'a, T, N> { #[inline] fn len(&self) -> usize { - (self.slice.len() + 1).saturating_sub(A::SIZE) + (self.slice.len() + 1).saturating_sub(N) } #[inline] #[cfg(feature = "nightly")] fn is_empty(&self) -> bool { - self.slice.len() < A::SIZE + self.slice.len() < N } } -impl<'a, A> fmt::Debug for ArrayWindows<'a, A> +impl<'a, T, const N: usize> fmt::Debug for ArrayWindows<'a, T, N> where - A: Array, - A::Item: fmt::Debug, + T: fmt::Debug, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ArrayWindows") .field("slice", &self.slice) - .field("window_len", &A::SIZE) + .field("window_len", &N) .finish() } } #[cfg(test)] mod tests { - use crate::Slice; + use crate::Continuous; #[test] fn basic_usage() { - let mut iter = [0, 1, 2, 3].array_windows::<[_; 2]>(); + let mut iter = [0, 1, 2, 3].array_windows_::<2>(); assert_eq!(iter.next(), Some(&[0, 1])); assert_eq!(iter.next(), Some(&[1, 2])); @@ -150,7 +137,7 @@ mod tests { #[test] fn back() { - let mut iter = [0, 1, 2, 3].array_windows::<[_; 2]>().rev(); + let mut iter = [0, 1, 2, 3].array_windows_::<2>().rev(); assert_eq!(iter.next(), Some(&[2, 3])); assert_eq!(iter.next(), Some(&[1, 2])); @@ -161,7 +148,7 @@ mod tests { #[test] fn destruct() { let res = [1, 2, 3] - .array_windows::<[_; 2]>() + .array_windows_::<2>() .fold(0, |i, [a, b]| i + (a * b)); assert_eq!(res, 8) @@ -169,7 +156,7 @@ mod tests { #[test] fn nth() { - let mut iter = [0, 1, 2, 3, 4, 5].array_windows::<[_; 2]>(); + let mut iter = [0, 1, 2, 3, 4, 5].array_windows_::<2>(); assert_eq!(iter.nth(3), Some(&[3, 4])); assert_eq!(iter.next(), Some(&[4, 5])); @@ -178,7 +165,7 @@ mod tests { #[test] fn nth_back() { - let mut iter = [0, 1, 2, 3, 4, 5].array_windows::<[_; 2]>(); + let mut iter = [0, 1, 2, 3, 4, 5].array_windows_::<2>(); assert_eq!(iter.nth_back(3), Some(&[1, 2])); assert_eq!(iter.next(), Some(&[0, 1])); @@ -187,7 +174,7 @@ mod tests { #[test] fn len() { - let mut iter = [0, 1, 2, 3, 4, 5].array_windows::<[_; 2]>(); + let mut iter = [0, 1, 2, 3, 4, 5].array_windows_::<2>(); assert_eq!(iter.len(), 5); iter.next(); iter.next_back(); diff --git a/src/lib.rs b/src/lib.rs index 1821f39..88442f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,21 +2,17 @@ //! 1) Abstraction over arrays (you can use [`Array`] trait as bound on //! generics) //! 2) Creation of arrays (see [`Array`] trait) -//! 3) Doing operations on arrays that produce arrays (see -//! [`ArrayMap`] and [`ArrayAsRef`] traits) -//! 4) By-value iterating on array (see [`IterMove`]) -//! 5) `Iterator` adapter that yield fixed sized chunks of inner iterator +//! 3) Doing operations on arrays that produce arrays +//! 4) `Iterator` adapter that yield fixed sized chunks of inner iterator //! (see [`ArrayChunks`]) //! //! [`Array`]: crate::Array -//! [`ArrayExt`]: crate::ArrayExt -//! [`IterMove`]: crate::iter::IterMove //! [`ArrayChunks`]: crate::iter::ArrayChunks //! //! ## Example //! //! ``` -//! use arraylib::{Array, ArrayExt, ArrayMap}; +//! use arraylib::Array; //! //! // Array creation //! let arr = <[_; 11]>::unfold(1, |it| { @@ -26,7 +22,7 @@ //! }); //! //! // Mapping -//! let arr = arr.map(|it| it * 2); +//! let arr = arr.lift(|it| it * 2); //! assert_eq!(arr, [2, -4, 8, -16, 32, -64, 128, -256, 512, -1024, 2048]); //! //! // By-value iterator @@ -79,7 +75,7 @@ //! and [`Array::from_iter`]) //! - [`array_ext`](https://docs.rs/array_ext) //! - [`slice_as_array`](https://peterreid.github.io/slice_as_array/slice_as_array/index.html) -//! (analogs to [`ArrayExt::from_slice`] and [`Array::from_iter`]) +//! (analogs to [`Array::from_slice`] and [`Array::from_iter`]) //! - [`arraytools`](https://docs.rs/arraytools) //! - [`core::array::FixedSizeArray`](https://doc.rust-lang.org/beta/core/array/trait.FixedSizeArray.html) //! - [`stackvec`](https://docs.rs/stackvec/) @@ -104,8 +100,6 @@ #![cfg_attr(not(test), no_std)] // Some sweaty nightly features #![cfg_attr(feature = "nightly", feature(trusted_len, exact_size_is_empty))] -// For running tests from readme -#![cfg_attr(all(doctest, feature = "nightly"), feature(external_doc))] // I hate missing docs #![deny(missing_docs)] // And I like inline @@ -116,7 +110,7 @@ // ```console // $ RUSTDOCFLAGS="--cfg docsrs" cargo doc --open --features "alloc nightly" // ``` -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(all(docsrs, feature = "nightly"), feature(doc_cfg))] #[cfg(feature = "alloc")] extern crate alloc; @@ -124,10 +118,6 @@ extern crate alloc; /// Utils that help implementing public API #[macro_use] pub(crate) mod util { - #[macro_use] - /// Helper macros these are used in this lib - mod local_macros; - /// Array initialization pub(crate) mod init; @@ -135,66 +125,44 @@ pub(crate) mod util { pub(crate) mod transmute; } -pub use self::{ - array::Array, - ext::{ - array_ext::ArrayExt, - shorthand::ArrayShorthand, - slice_ext::{MaybeUninitSlice, Slice}, - }, - transform::{as_ref::ArrayAsRef, map::ArrayMap}, - wrap::ArrayWrapper, -}; +pub use self::{array::Array, continuous::Continuous}; /// Iterator related things pub mod iter { - pub use self::{ - chunks::ArrayChunks, ext::IteratorExt, iter_move::IterMove, windows::ArrayWindows, - }; + pub use self::{chunks::ArrayChunks, ext::IteratorExt, windows::ArrayWindows}; mod chunks; mod ext; - mod iter_move; mod windows; } -// === private but reexported === +// private but reexported mod array; -mod wrap; - -/// Array transformers like map (`[T; N]` -> `[U; N]`) -/// -/// Commonly just shortcuts for `.iter_move().*method*(...).collect_array()` -mod transform { - /// `&(mut) [T; N]` -> `[&(mut) T; N]` - pub(super) mod as_ref; - /// `[T; N]` -> `[U; N]` - pub(super) mod map; -} - -/// Different extension traits -mod ext { - /// Array ext - pub(super) mod array_ext; - /// Also array ext (but for `.as_slice().method()` -> `.method()` shortcuts) - pub(super) mod shorthand; - /// Slice ext - pub(super) mod slice_ext; -} +mod continuous; /// Run tests from readme -#[cfg_attr(feature = "nightly", doc(include = "../README.md"))] +#[cfg_attr(feature = "nightly", doc = include_str!("../README.md"))] #[cfg(doctest)] pub struct ReadmeDocTests; /// Error that is caused by wrong sizes of slices/arrays -#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)] -pub struct SizeError(()); +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[non_exhaustive] +pub struct SizeError { + /// Actuall size + pub found: usize, + /// Expected size + pub expected: usize, +} impl core::fmt::Display for SizeError { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - f.write_str("wrong size") + write!( + f, + "wrong size, expected {}, found {}", + self.expected, self.found + ) } } diff --git a/src/transform/as_ref.rs b/src/transform/as_ref.rs deleted file mode 100644 index f55f246..0000000 --- a/src/transform/as_ref.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::{iter::IteratorExt, Array}; - -/// Trait for conversation between `&[T; N]` and `[&T; N]` (or `&mut [T; N]` and -/// `[&mut T; N]`) -pub trait ArrayAsRef<'a>: Array -where - ::Item: 'a, -{ - /// Result of the 'shared' conversation, in other words `[&T; N]` - /// (where `T = Self::Item, N = Self::Size`) - type AsRef: Array::Item>; - - /// Result of the 'unique' conversation, in other words `[&mut T; N]` - /// (where `T = Self::Item, N = Self::Size`) - type AsMut: Array::Item>; - - /// Convert `&self` to `[&T; N]` (where `T = Self::Item, N = Self::Size`) - /// - /// ## Examples - /// ``` - /// use arraylib::ArrayAsRef; - /// - /// let arr = [0, 1, 2, 3]; - /// let ref_arr = arr.as_ref_array(); - /// assert_eq!(ref_arr, [&0, &1, &2, &3]); - /// assert_eq!(arr, [0, 1, 2, 3]); - /// ``` - /// ``` - /// use arraylib::{ArrayAsRef, ArrayExt}; - /// - /// // Don't do like this, it's just an example - /// fn index_of(a: &A, x: A::Item) -> Option - /// where - /// for<'a> A: ArrayAsRef<'a>, - /// A::Item: PartialEq, - /// { - /// a.as_ref_array() - /// .iter_move() - /// .enumerate() - /// .find(|&(_, it)| it == &x) - /// .map(|(idx, _)| idx) - /// } - /// - /// let arr = [-2, 1, -1, 2]; - /// assert_eq!(index_of(&arr, 1), Some(1)); - /// assert_eq!(index_of(&arr, 2), Some(3)); - /// assert_eq!(index_of(&arr, 0), None); - /// ``` - /// - /// **NOTE**: it's nighly recommended to use iterators when you need to - /// perform more that one operation (e.g. map + as_ref) because iterators - /// are lazy and `ArrayAsRef` isn't. - /// - /// See also: [`as_mut_array`](crate::ArrayAsRef::as_mut_array) - fn as_ref_array(&'a self) -> Self::AsRef; - - /// Convert `&mut self` to `[&mut T; N]` (where `T = Self::Item, N = - /// Self::Size`) - /// - /// ## Examples - /// ``` - /// use arraylib::ArrayAsRef; - /// - /// let mut arr = [0, 1, 2, 3]; - /// let ref_arr = arr.as_mut_array(); - /// assert_eq!(ref_arr, [&mut 0, &mut 1, &mut 2, &mut 3]); - /// assert_eq!(arr, [0, 1, 2, 3]); - /// ``` - /// ``` - /// use arraylib::{ArrayAsRef, ArrayExt}; - /// - /// // Don't do like this, it's just an example - /// fn find_and_replace(a: &mut A, find: &A::Item, replace: A::Item) -> A::Item - /// where - /// for<'a> A: ArrayAsRef<'a>, - /// A::Item: PartialEq, - /// { - /// let mut x = a.as_mut_array().iter_move().find(|it| it == &find); - /// match x { - /// Some(ref mut inner) => core::mem::replace(inner, replace), - /// None => replace, - /// } - /// } - /// - /// let mut arr = [-2, 1, -1, 2]; - /// assert_eq!(find_and_replace(&mut arr, &1, 8), 1); - /// assert_eq!(arr, [-2, 8, -1, 2]); - /// ``` - /// - /// **NOTE**: it's nighly recommended to use iterators when you need to - /// perform more that one operation (e.g. map + as_ref) because iterators - /// are lazy and `ArrayAsRef` isn't. - /// - /// See also: [`as_ref_array`](crate::ArrayAsRef::as_ref_array) - fn as_mut_array(&'a mut self) -> Self::AsMut; -} - -impl<'a, T: 'a> ArrayAsRef<'a> for [T; 0] { - type AsMut = [&'a mut T; 0]; - type AsRef = [&'a T; 0]; - - #[inline] - fn as_ref_array(&'a self) -> Self::AsRef { - [] - } - - #[inline] - fn as_mut_array(&'a mut self) -> Self::AsMut { - [] - } -} - -macro_rules! as_ref_impl { - ($e:tt) => { - impl<'a, T: 'a> ArrayAsRef<'a> for [T; $e] { - type AsMut = [&'a mut T; $e]; - type AsRef = [&'a T; $e]; - - #[inline] - fn as_ref_array(&'a self) -> Self::AsRef { - self.as_slice().iter().collect_array::() - } - - #[inline] - fn as_mut_array(&'a mut self) -> Self::AsMut { - self.as_mut_slice() - .iter_mut() - .collect_array::() - } - } - }; -} - -array_impls!(as_ref_impl); diff --git a/src/transform/map.rs b/src/transform/map.rs deleted file mode 100644 index afc2c57..0000000 --- a/src/transform/map.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::{iter::IteratorExt, Array, ArrayExt}; - -/// Represent array which elements can be mapped (actually any array) -pub trait ArrayMap: Array { - /// Type of mapped array. So if `Self = [T; N]` then `Map = [U; N]` - /// i.e. - /// ``` - /// # use arraylib::ArrayMap; fn dummy() where - /// [T; 4]: ArrayMap - /// # {} - /// ``` - type Map: Array; - - /// Maps elements of the array - /// - /// ## Examples - /// ``` - /// use arraylib::ArrayMap; - /// - /// let arr = [1, 2, 3, 4, 5]; - /// let res = arr.map(|x| 2i32.pow(x)); - /// assert_eq!(res, [2, 4, 8, 16, 32]) - /// ``` - /// - /// **NOTE**: it's nighly recommended to use iterators when you need to - /// perform more that one operation (e.g. map + as_ref) because iterators - /// are lazy and `ArrayMap` isn't. - #[inline] - fn map(self, f: F) -> Self::Map - where - F: FnMut(Self::Item) -> U, - { - // It's probably not the best implementation (if you are mad on - // performance) due to checks that can be not eliminated, but - // `collect_array` (`from_iter`) catch all the tricky stuff - // about memory leaks, so this simple implementation was chosen. - // - // In future this implementation may be overwritten for small array - // sizes using macros. - self.iter_move().map(f).collect_array() - } -} - -impl ArrayMap for [T; 0] { - type Map = [U; 0]; - - #[inline] - fn map(self, _f: F) -> Self::Map - where - F: FnMut(Self::Item) -> U, - { - [] - } -} - -macro_rules! array_map_impl { - ($SIZE:expr) => { - impl ArrayMap for [T; $SIZE] { - type Map = [U; $SIZE]; - } - }; -} - -array_impls!(array_map_impl); diff --git a/src/util/init.rs b/src/util/init.rs index f81c7fb..b73cd3a 100644 --- a/src/util/init.rs +++ b/src/util/init.rs @@ -10,67 +10,22 @@ //! [`from_fn`]: crate::Array::from_fn //! [`from_iter`]: crate::Array::from_iter use core::{ - convert::Infallible, mem::{self, MaybeUninit}, ptr, }; -use crate::{Array, ArrayShorthand, MaybeUninitSlice}; +use crate::{Array, Continuous}; #[inline] -pub(crate) fn array_init_fn(mut init: F) -> Arr +pub(crate) fn try_unfold_array(init: St, mut f: F) -> Result<[T; N], E> where - Arr: Array, - Arr::Item: Sized, - F: FnMut(usize) -> Arr::Item, -{ - try_array_init_fn(|i| Ok::<_, Infallible>(init(i))).unwrap_or_else(|inf| match inf {}) -} - -#[inline] -pub(crate) fn array_init_iter(mut iter: I) -> Option -where - Arr: Array, - Arr::Item: Sized, - I: Iterator, -{ - try_unfold_array((), |_| iter.next().ok_or(())).ok() -} - -#[inline] -pub(crate) fn try_array_init_fn(mut f: F) -> Result -where - Arr: Array, - Arr::Item: Sized, - F: FnMut(usize) -> Result, -{ - try_unfold_array(0usize, |state| { - let item = f(*state); - *state += 1; - item - }) -} - -#[inline] -pub(crate) fn unfold_array(init: St, mut f: F) -> Arr -where - Arr: Array, - F: FnMut(&mut St) -> Arr::Item, -{ - try_unfold_array(init, |state| Ok::<_, Infallible>(f(state))).unwrap_or_else(|inf| match inf {}) -} - -#[inline] -pub(crate) fn try_unfold_array(init: St, mut f: F) -> Result -where - Arr: Array, // It's better to use `Try` here, instead of `Result` but it's unstable - F: FnMut(&mut St) -> Result, + F: FnMut(&mut St) -> Result, { - let mut array = Arr::uninit(); + let mut array: [MaybeUninit; N] = <[T; N]>::uninit(); let mut state = init; - if !mem::needs_drop::() { + if !mem::needs_drop::() { for hole in array.iter_mut() { // If `init` panics/fails nothing really happen: panic/fail just go up // (Item doesn't need drop, so there are no leaks and everything is ok') @@ -89,18 +44,21 @@ where /// dropped /// - ...so it must be sound to drop these elements using /// `ptr::drop_in_place` - struct DropGuard<'a, Item> { - arr: &'a mut [MaybeUninit], + struct DropGuard<'a, T, const N: usize> { + arr: &'a mut [MaybeUninit; N], initialized: usize, } - impl Drop for DropGuard<'_, Item> { + impl Drop for DropGuard<'_, T, N> { fn drop(&mut self) { + debug_assert!(self.initialized <= N); + // ## Safety // // The contract of the struct guarantees that this is sound unsafe { - let inited: &mut [Item] = self.arr[..self.initialized].assume_init_mut(); + let inited: &mut [T] = + <[_]>::assume_init_mut(self.arr.get_unchecked_mut(..self.initialized)); // drop initialized elements ptr::drop_in_place(inited); @@ -116,7 +74,7 @@ where // By construction, `array[..initialized]` only contains // init elements, thus there is no risk of dropping uninit data. let mut guard = DropGuard { - arr: array.as_mut_slice(), + arr: &mut array, initialized: 0, }; @@ -141,7 +99,7 @@ where // ## Safety // // We already initialized all elements of the array - Ok(Arr::assume_init(array)) + Ok(<[T; N]>::assume_init(array)) } } @@ -153,8 +111,7 @@ mod tests { use core::convert::TryFrom; use std::sync::Mutex; - use super::{array_init_fn, try_array_init_fn}; - use crate::util::init::array_init_iter; + use crate::Array; /// Add `1` to mutex on drop #[derive(Debug)] @@ -169,7 +126,7 @@ mod tests { #[test] fn copy() { - let arr: [i32; 32] = super::try_array_init_fn(i32::try_from).unwrap(); + let arr: [i32; 32] = Array::try_from_fn(i32::try_from).unwrap(); assert_eq!( arr, @@ -188,7 +145,7 @@ mod tests { fn drop(&mut self) {} } - let _: [HasDrop; 16] = array_init_fn(|_| HasDrop); + let _: [HasDrop; 16] = Array::from_fn(|_| HasDrop); } #[test] @@ -196,7 +153,7 @@ mod tests { let counter = Mutex::new(0); let r = std::panic::catch_unwind(|| { - let _: [DropCount; 16] = array_init_fn(|i| { + let _: [DropCount; 16] = Array::from_fn(|i| { if i == 10 { panic!() } else { @@ -213,7 +170,7 @@ mod tests { fn drop_on_fail() { let counter = Mutex::new(0); - let r: Result<[DropCount; 16], ()> = try_array_init_fn(|i| { + let r: Result<[DropCount; 16], ()> = Array::try_from_fn(|i| { if i == 10 { Err(()) } else { @@ -227,18 +184,18 @@ mod tests { #[test] fn zst() { - let _: [(); 65536] = array_init_fn(|_| ()); + let _: [(); 65536] = Array::from_fn(|_| ()); } #[test] fn the_biggest() { - let _: [usize; 16384] = array_init_fn(|i| i); + let _: [usize; 16384] = Array::from_fn(|i| i); } #[test] fn iter_equal_len() { let mut vec = vec![0, 1, 2, 3, 4]; - let arr: [i32; 5] = array_init_iter(vec.drain(..)).unwrap(); + let arr: [i32; 5] = Array::from_iter(vec.drain(..)).unwrap(); assert_eq!(arr, [0, 1, 2, 3, 4]); } @@ -246,7 +203,7 @@ mod tests { #[test] fn iter_greater_len() { let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8]; - let arr: [i32; 5] = array_init_iter(vec.drain(..)).unwrap(); + let arr: [i32; 5] = Array::from_iter(vec.drain(..)).unwrap(); assert_eq!(arr, [0, 1, 2, 3, 4]); } @@ -254,7 +211,7 @@ mod tests { #[test] fn iter_less_len() { let mut vec = vec![0, 1, 2]; - let arr: Option<[i32; 5]> = array_init_iter(vec.drain(..)); + let arr: Option<[i32; 5]> = Array::from_iter(vec.drain(..)); assert_eq!(arr, None); } diff --git a/src/util/local_macros.rs b/src/util/local_macros.rs deleted file mode 100644 index ed2b859..0000000 --- a/src/util/local_macros.rs +++ /dev/null @@ -1,194 +0,0 @@ -/// Calls a `$callback` with sizes of the arrays for which traits must be -/// implemented -macro_rules! array_impls { - ($callback:ident) => { - // impls for arrays of sizes [1..32] (size = 0 is always implemented by hands) - impls_inner!( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32; - $callback - ); - - // Some useful impls - impls_inner!( - 40, // 8 * 5 - 48, // 8 * 6 - 56, // 8 * 7 - 64, // 8 * 8 - 72, // 8 * 9 - 80, // 8 * 10 - 88, // 8 * 11 - 96, // 8 * 12 - - 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, // 100 * n, n <- [1..10] - - 128, // 2 ** 7 - 256, // 2 ** 8 - 512, // 2 ** 9 - 1024, // 2 ** 10 - 2048, // 2 ** 11 - 4096, // 2 ** 12 - 8192, // 2 ** 13 - 16384, // 2 ** 14 - 32768, // 2 ** 15 - 65536 // 2 ** 16 - ; - $callback - ); - - // impls for arrays of sizes [33..128] (except sizes that implemented by default) - #[cfg(feature = "array-impls-33-128")] - impls_inner!( - 33, 34, 35, 36, 37, 38, 39, /* 40, */ 41, 42, 43, 44, 45, 46, 47, /* 48, */ 49, 50, 51, - 52, 53, 54, 55, /* 56, */ 57, 58, 59, 60, 61, 62, 63, /* 64, */ 65, 66, 67, 68, 69, 70, - 71, /* 72, */ 73, 74, 75, 76, 77, 78, 79, /* 80, */ 81, 82, 83, 84, 85, 86, 87, - /* 88, */ 89, 90, 91, 92, 93, 94, 95, /* 96, */ 97, 98, 99, /* 100, */ 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127 /*, 128 */; - $callback - ); - - // impls for arrays of sizes [129..255] (except sizes that implemented by default) - #[cfg(feature = "array-impls-33-256")] - impls_inner!( - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256; - $callback - ); - }; -} - -/// helper for `array_impls!` -macro_rules! impls_inner { - ($( $size:tt ),+; $callback:ident) => { - $( - $callback!($size); - )+ - }; -} - -#[rustfmt::skip] -macro_rules! block_specialisation { - (0, $b:block) => { compile_error!("please init empty array properly") }; - // Fast path for sizes 1..32 - (1, $f:ident, $b:block) => { [$b] }; - (2, $f:ident, $b:block) => { [$b, $b] }; - (3, $f:ident, $b:block) => { [$b, $b, $b] }; - (4, $f:ident, $b:block) => { [$b, $b, $b, $b] }; - (5, $f:ident, $b:block) => { [$b, $b, $b, $b, $b] }; - (6, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b] }; - (7, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b] }; - (8, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b] }; - (9, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (10, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (11, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (12, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (13, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (14, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (15, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (16, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (17, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (18, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (19, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (20, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (21, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (22, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (23, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (24, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (25, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (26, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (27, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (28, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (29, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (30, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (31, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - (32, $f:ident, $b:block) => { [$b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b, $b] }; - - ($size:literal, $f:block, $b:block) => { $f }; -} - -#[rustfmt::skip] -macro_rules! from_fn_specialisation { - (0, $f:ident) => { compile_error!("please init empty array properly") }; - // Fast path for sizes 1..32 - (1, $f:ident) => { [$f(0)] }; - (2, $f:ident) => { [$f(0), $f(1)] }; - (3, $f:ident) => { [$f(0), $f(1), $f(2)] }; - (4, $f:ident) => { [$f(0), $f(1), $f(2), $f(3)] }; - (5, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4)] }; - (6, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5)] }; - (7, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6)] }; - (8, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7)] }; - (9, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8)] }; - (10, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9)] }; - (11, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10)] }; - (12, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11)] }; - (13, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12)] }; - (14, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13)] }; - (15, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14)] }; - (16, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15)] }; - (17, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16)] }; - (18, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17)] }; - (19, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18)] }; - (20, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19)] }; - (21, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20)] }; - (22, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21)] }; - (23, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22)] }; - (24, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23)] }; - (25, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23), $f(24)] }; - (26, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23), $f(24), $f(25)] }; - (27, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23), $f(24), $f(25), $f(26)] }; - (28, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23), $f(24), $f(25), $f(26), $f(27)] }; - (29, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23), $f(24), $f(25), $f(26), $f(27), $f(28)] }; - (30, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23), $f(24), $f(25), $f(26), $f(27), $f(28), $f(29)] }; - (31, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23), $f(24), $f(25), $f(26), $f(27), $f(28), $f(29), $f(30)] }; - (32, $f:ident) => { [$f(0), $f(1), $f(2), $f(3), $f(4), $f(5), $f(6), $f(7), $f(8), $f(9), $f(10), $f(11), $f(12), $f(13), $f(14), $f(15), $f(16), $f(17), $f(18), $f(19), $f(20), $f(21), $f(22), $f(23), $f(24), $f(25), $f(26), $f(27), $f(28), $f(29), $f(30), $f(31)] }; - - ($size:literal, $f:ident) => { $crate::util::init::array_init_fn($f) }; -} - -#[rustfmt::skip] -macro_rules! try_from_fn_specialisation { - (0, $f:ident) => { compile_error!("please init empty array properly") }; - // Fast path for sizes 1..32 - (1, $f:ident) => { [$f(0)?] }; - (2, $f:ident) => { [$f(0)?, $f(1)?] }; - (3, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?] }; - (4, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?] }; - (5, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?] }; - (6, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?] }; - (7, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?] }; - (8, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?] }; - (9, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?] }; - (10, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?] }; - (11, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?] }; - (12, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?] }; - (13, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?] }; - (14, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?] }; - (15, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?] }; - (16, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?] }; - (17, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?] }; - (18, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?] }; - (19, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?] }; - (20, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?] }; - (21, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?] }; - (22, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?] }; - (23, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?] }; - (24, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?] }; - (25, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?, $f(24)?] }; - (26, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?, $f(24)?, $f(25)?] }; - (27, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?, $f(24)?, $f(25)?, $f(26)?] }; - (28, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?, $f(24)?, $f(25)?, $f(26)?, $f(27)?] }; - (29, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?, $f(24)?, $f(25)?, $f(26)?, $f(27)?, $f(28)?] }; - (30, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?, $f(24)?, $f(25)?, $f(26)?, $f(27)?, $f(28)?, $f(29)?] }; - (31, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?, $f(24)?, $f(25)?, $f(26)?, $f(27)?, $f(28)?, $f(29)?, $f(30)?] }; - (32, $f:ident) => { [$f(0)?, $f(1)?, $f(2)?, $f(3)?, $f(4)?, $f(5)?, $f(6)?, $f(7)?, $f(8)?, $f(9)?, $f(10)?, $f(11)?, $f(12)?, $f(13)?, $f(14)?, $f(15)?, $f(16)?, $f(17)?, $f(18)?, $f(19)?, $f(20)?, $f(21)?, $f(22)?, $f(23)?, $f(24)?, $f(25)?, $f(26)?, $f(27)?, $f(28)?, $f(29)?, $f(30)?, $f(31)?] }; - - ($size:literal, $f:ident) => { $crate::util::init::try_array_init_fn($f)? }; -} diff --git a/src/wrap.rs b/src/wrap.rs deleted file mode 100644 index fd2091f..0000000 --- a/src/wrap.rs +++ /dev/null @@ -1,552 +0,0 @@ -use core::{ - borrow::{Borrow, BorrowMut}, - cmp::Ordering, - convert::TryFrom, - fmt, hash, - hash::Hash, - ops::{Index, IndexMut}, - slice::SliceIndex, -}; - -use crate::{iter::IterMove, Array, ArrayExt, ArrayShorthand, SizeError}; - -/// Wrapper over array types. It implements the same[^1] traits as -/// [`array`], but not for only arrays of sizes `0..=32` but **for all arrays, -/// those sizes are supported by the crate**[^2]: -/// - [`Debug`] -/// - [`IntoIterator`] -/// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] -/// - [`Hash`] -/// - [`AsRef`], [`AsMut`] (both for `A` and `[A::Item]`) -/// - [`Borrow`], [`BorrowMut`] -/// - [`Index`], [`IndexMut`] -/// - [`Default`] -/// - [`TryFrom`] -/// -/// Note: Implementations of the most trai just copy-pasted from std -/// -/// [`array`]: https://doc.rust-lang.org/std/primitive.array.html -/// [`Debug`]: core::fmt::Debug -/// [`IntoIterator`]: core::iter::IntoIterator -/// [`PartialEq`]: core::cmp::PartialEq -/// [`PartialOrd`]: core::cmp::PartialOrd -/// [`Eq`]: core::cmp::Eq -/// [`Ord`]: core::cmp::Ord -/// [`Hash`]: core::hash::Hash -/// [`AsRef`]: core::convert::AsRef -/// [`AsMut`]: core::convert::AsMut -/// [`Borrow`]: core::borrow::Borrow -/// [`BorrowMut`]: core::borrow::BorrowMut -/// [`Index`]: core::ops::Index -/// [`IndexMut`]: core::ops::IndexMut -/// [`Default`]: core::default::Default -/// [`TryFrom`]: core::convert::TryFrom -/// -/// ## Examples -/// -/// [`PartialEq`]/[`Eq`] : -/// ``` -/// use arraylib::{ArrayExt, ArrayWrapper}; -/// -/// let arr = [1, 2, 3].wrap(); -/// assert_eq!(arr, [1, 2, 3]); -/// assert_eq!(format!("{:?}", arr), "[1, 2, 3]"); -/// assert!(arr < [1, 4, 0]); -/// assert_eq!(arr[1], 2); -/// -/// assert!(arr.into_iter().eq(vec![1, 2, 3].into_iter())); -/// -/// assert_eq!( as Default>::default(), [0, 0, 0]); -/// ``` -/// -/// ``` -/// use arraylib::{ArrayExt, ArrayWrapper}; -/// use std::borrow::{Borrow, BorrowMut}; -/// -/// let mut arr = [1, 2, 3].wrap(); -/// -/// let slice: &[i32] = arr.as_ref(); -/// assert_eq!(slice, &[1, 2, 3]); -/// ``` -/// ``` -/// use arraylib::ArrayExt; -/// use std::{ -/// collections::hash_map::DefaultHasher, -/// hash::{Hash, Hasher}, -/// }; -/// -/// let mut hasher = DefaultHasher::new(); -/// [1, 2, 3].wrap().hash(&mut hasher); -/// let hash0 = hasher.finish(); -/// -/// let mut hasher = DefaultHasher::new(); -/// [1, 2, 3].hash(&mut hasher); -/// let hash1 = hasher.finish(); -/// -/// assert_eq!(hash0, hash1); -/// ``` -/// In difference with std, `ArrayWrapper` _is_ iterable: -/// ``` -/// use arraylib::ArrayExt; -/// -/// let arr = [0, 3, 45, 91].wrap(); -/// for x in arr {} -/// ``` -// [^2] goes before [^1] because otherwise rustdoc parses it the wrong way ¯\_(ツ)_/¯ -/// -/// [^2]: See [Sizes Limitations](./index.html#sizes-limitations) paragraph in -/// crate docs. -/// -/// [^1]: differences: -/// - IntoIterator (on std's [`array`] `IntoIterator` is implemented only on -/// `&[T; N]` and on `&mut [T; N]` while on ArrayWrapper it's implemented -/// directly (using [`IterMove`])) -/// - In some traits instead of [`TryFromSliceError`] there is [`SizeError`] -/// - [`Copy`]/[`Clone`] are implemented only when `A: Copy/Clone` and not -/// when `A::Item: Copy/Clone` because we can't use compiler magic :( -/// -/// [`TryFromSliceError`]: core::array::TryFromSliceError -/// [`SizeError`]: crate::SizeError -/// [`IterMove`]: crate::iter::IterMove -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct ArrayWrapper { - array: A, -} - -impl ArrayWrapper -where - A: Array, -{ - /// Create new `ArrayWrapper` - /// - /// ``` - /// use arraylib::ArrayWrapper; - /// - /// let arr = ArrayWrapper::new([0, 1, 2, 3]); - /// println!("{:?}", arr); - /// ``` - #[inline] - pub fn new(inner: A) -> Self { - Self { array: inner } - } - - /// Destruct `ArrayWrapper` into inner array - /// - /// ``` - /// use arraylib::ArrayWrapper; - /// - /// let arr = ArrayWrapper::new([0, 1, 2, 3]); - /// // ... - /// let arr = arr.into_inner(); - /// println!("{:?}", arr); - /// ``` - #[inline] - pub fn into_inner(self) -> A { - self.array - } -} - -impl AsRef for ArrayWrapper { - #[inline] - fn as_ref(&self) -> &A { - &self.array - } -} - -impl AsMut for ArrayWrapper { - #[inline] - fn as_mut(&mut self) -> &mut A { - &mut self.array - } -} - -impl AsRef<[A::Item]> for ArrayWrapper -where - A: Array, -{ - #[inline] - fn as_ref(&self) -> &[A::Item] { - &self[..] - } -} - -impl AsMut<[A::Item]> for ArrayWrapper -where - A: Array, -{ - #[inline] - fn as_mut(&mut self) -> &mut [A::Item] { - &mut self[..] - } -} - -impl Borrow<[A::Item]> for ArrayWrapper -where - A: Array, -{ - #[inline] - fn borrow(&self) -> &[A::Item] { - self.as_slice() - } -} - -impl BorrowMut<[A::Item]> for ArrayWrapper -where - A: Array, -{ - #[inline] - fn borrow_mut(&mut self) -> &mut [A::Item] { - self.as_mut_slice() - } -} - -impl Default for ArrayWrapper -where - A: Array, - A::Item: Default, -{ - #[inline] - fn default() -> Self { - <_>::from_fn(|_| <_>::default()) - } -} - -impl TryFrom<&[A::Item]> for ArrayWrapper -where - A::Item: Copy, - A: Array, -{ - type Error = SizeError; - - #[inline] - fn try_from(slice: &[A::Item]) -> Result { - Self::from_slice(slice) - } -} - -/// Alias for [`ArrayExt::try_ref_cast`][alias] -/// -/// [alias]: crate::ArrayExt::try_ref_cast -/// -/// ## Examples -/// -/// ``` -/// use arraylib::ArrayWrapper; -/// use core::convert::TryInto; -/// -/// let slice = &[0, 1, 2][..]; -/// let arr: &ArrayWrapper<[i32; 3]> = slice.try_into().unwrap(); -/// assert_eq!(arr, &ArrayWrapper::new([0, 1, 2])) -/// ``` -impl<'a, A> TryFrom<&'a [A::Item]> for &'a ArrayWrapper -where - A: Array, -{ - type Error = &'a [A::Item]; - - #[inline] - fn try_from(slice: &'a [A::Item]) -> Result { - <_>::try_ref_cast(slice) - } -} - -/// Alias for [`ArrayExt::try_mut_cast`][alias] -/// -/// [alias]: crate::ArrayExt::try_mut_cast -/// -/// ## Examples -/// -/// ``` -/// use arraylib::ArrayWrapper; -/// use core::convert::TryInto; -/// -/// let slice = &mut [0, 1, 2][..]; -/// let arr: &mut ArrayWrapper<[i32; 3]> = slice.try_into().unwrap(); -/// assert_eq!(arr, &ArrayWrapper::new([0, 1, 2])) -/// ``` -impl<'a, A> TryFrom<&'a mut [A::Item]> for &'a mut ArrayWrapper -where - A: Array, -{ - type Error = &'a mut [A::Item]; - - #[inline] - fn try_from(slice: &'a mut [A::Item]) -> Result { - <_>::try_mut_cast(slice) - } -} - -impl Hash for ArrayWrapper -where - A::Item: Hash, - A: Array, -{ - #[inline] - fn hash(&self, state: &mut H) { - Hash::hash(&self[..], state) - } -} - -impl Eq for ArrayWrapper -where - A: Array, - A::Item: Eq, -{ -} - -impl PartialOrd for ArrayWrapper -where - A: Array, - B: Array, /* for some reason there is no impl of PartialOrd<[B]> for [A] - * where A: PartialOrd */ - A::Item: PartialOrd, -{ - #[inline] - fn partial_cmp(&self, other: &B) -> Option { - PartialOrd::partial_cmp(&self[..], other.as_slice()) - } - - #[inline] - fn lt(&self, other: &B) -> bool { - PartialOrd::lt(&self[..], other.as_slice()) - } - - #[inline] - fn le(&self, other: &B) -> bool { - PartialOrd::le(&self[..], other.as_slice()) - } - - #[inline] - fn gt(&self, other: &B) -> bool { - PartialOrd::gt(&self[..], other.as_slice()) - } - - #[inline] - fn ge(&self, other: &B) -> bool { - PartialOrd::ge(&self[..], other.as_slice()) - } -} - -impl Ord for ArrayWrapper -where - A: Array, - A::Item: Ord, -{ - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - Ord::cmp(&&self[..], &&other[..]) - } -} - -impl fmt::Debug for ArrayWrapper -where - A::Item: fmt::Debug, - A: Array, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&&self[..], f) - } -} - -impl IntoIterator for ArrayWrapper -where - A: Array, -{ - type IntoIter = IterMove; - type Item = A::Item; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - IterMove::new(self) - } -} - -impl PartialEq for ArrayWrapper -where - A::Item: PartialEq, - A: Array, - B: Array, -{ - #[inline] - fn eq(&self, other: &B) -> bool { - &self[..] == other.as_slice() - } -} - -impl PartialEq> for [T] -where - T: PartialEq, - A: Array, -{ - #[inline] - fn eq(&self, other: &ArrayWrapper) -> bool { - self[..] == other[..] - } -} - -impl<'t, A, T> PartialEq<&'t [T]> for ArrayWrapper -where - A::Item: PartialEq, - A: Array, -{ - #[inline] - fn eq(&self, other: &&'t [T]) -> bool { - self[..] == other[..] - } -} - -impl<'t, A, T> PartialEq> for &'t [T] -where - T: PartialEq, - A: Array, -{ - #[inline] - fn eq(&self, other: &ArrayWrapper) -> bool { - self[..] == other[..] - } -} - -impl<'t, A, T> PartialEq<&'t mut [T]> for ArrayWrapper -where - A::Item: PartialEq, - A: Array, -{ - #[inline] - fn eq(&self, other: &&'t mut [T]) -> bool { - self[..] == other[..] - } -} - -impl<'t, A, T> PartialEq> for &'t mut [T] -where - T: PartialEq, - A: Array, -{ - #[inline] - fn eq(&self, other: &ArrayWrapper) -> bool { - self[..] == other[..] - } -} - -impl PartialEq<[T]> for ArrayWrapper -where - A::Item: PartialEq, - A: Array, -{ - #[inline] - fn eq(&self, other: &[T]) -> bool { - self[..] == other[..] - } -} - -/// ## Safety -/// -/// `ArrayWrapper` has `#[repr(transparent)]` so it has the same ABI as `A`. -/// So if `A` is array then so is `ArrayWrapper`. -unsafe impl Array for ArrayWrapper -where - A: Array, -{ - type Item = A::Item; - type Maybe = ArrayWrapper; - - const SIZE: usize = A::SIZE; - - crate::if_alloc! { - #[inline] - fn into_boxed_slice(self) -> alloc::boxed::Box<[Self::Item]> { - self.array.into_boxed_slice() - } - } - - #[inline] - fn as_slice(&self) -> &[Self::Item] { - self.array.as_slice() - } - - #[inline] - fn as_mut_slice(&mut self) -> &mut [Self::Item] { - self.array.as_mut_slice() - } - - #[inline] - fn try_unfold(init: St, f: F) -> Result - where - F: FnMut(&mut St) -> Result, - { - Ok(Self { - array: A::try_unfold(init, f)?, - }) - } - - #[inline] - fn unfold(init: St, f: F) -> Self - where - F: FnMut(&mut St) -> Self::Item, - { - Self { - array: A::unfold(init, f), - } - } - - #[inline] - fn try_from_fn(f: F) -> Result - where - F: FnMut(usize) -> Result, - { - Ok(Self { - array: A::try_from_fn(f)?, - }) - } - - #[inline] - fn from_fn(f: F) -> Self - where - F: FnMut(usize) -> Self::Item, - { - Self { - array: A::from_fn(f), - } - } - - #[inline] - fn try_from_iter(iter: I) -> Option - where - I: IntoIterator, - { - A::try_from_iter(iter.into_iter()).map(|array| Self { array }) - } - - #[inline] - fn into_uninit(self) -> Self::Maybe { - Self::Maybe { - array: self.array.into_uninit(), - } - } -} - -impl Index for ArrayWrapper -where - A: Array, - Idx: SliceIndex<[A::Item]>, -{ - type Output = Idx::Output; - - #[inline] - fn index(&self, index: Idx) -> &Self::Output { - self.array.index(index) - } -} - -impl IndexMut for ArrayWrapper -where - A: Array, - Idx: SliceIndex<[A::Item]>, -{ - #[inline] - fn index_mut(&mut self, index: Idx) -> &mut Self::Output { - self.array.index_mut(index) - } -}