use std::mem::MaybeUninit;
pub trait SplitOwned<T> {
fn split_owned<const K: usize, const L: usize>(self) -> ([T; K], [T; L]);
}
impl<T, const N: usize> SplitOwned<T> for [T; N] {
fn split_owned<const K: usize, const L: usize>(self) -> ([T; K], [T; L]) {
const { assert!(N == K + L,
"Length of original array has to be equal to sum of lengths of resulting arrays N == K + L"
)};
let mut arr: [MaybeUninit<T>; N] = self.map(|el| MaybeUninit::new(el));
let mut arr_k: [MaybeUninit<T>; K] = std::array::from_fn(|_| MaybeUninit::uninit());
let mut arr_l: [MaybeUninit<T>; L] = std::array::from_fn(|_| MaybeUninit::uninit());
for i in 0..K {
std::mem::swap(&mut arr_k[i], &mut arr[i]);
}
for i in 0..L {
std::mem::swap(&mut arr_l[i], &mut arr[i + K]);
}
let arr_k: [T; K] = arr_k.map(|el: MaybeUninit<T> | unsafe { el.assume_init() });
let arr_l: [T; L] = arr_l.map(|el: MaybeUninit<T> | unsafe { el.assume_init() });
(arr_k, arr_l)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn split_easy() {
let arr: [f64; 19] = std::array::from_fn(|n| n as f64);
let (arr1, arr2) = arr.split_owned::<10, 9>();
assert_eq!(arr1, [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]);
assert_eq!(arr2, [10., 11., 12., 13., 14., 15., 16., 17., 18.]);
}
#[test]
fn split_zero() {
let arr: [f64; 6] = std::array::from_fn(|n| n as f64);
let (arr1, arr2) = arr.split_owned::<0, 6>();
assert_eq!(arr1, []);
assert_eq!(arr2, [0., 1., 2., 3., 4., 5.]);
let (arr1, arr2) = arr2.split_owned::<6, 0>();
assert_eq!(arr1, [0., 1., 2., 3., 4., 5.]);
assert_eq!(arr2, []);
}
#[test]
fn split_ref() {
let arr: [f64; 6] = std::array::from_fn(|n| n as f64);
let refs: [&f64; 6] = [&arr[0], &arr[1], &arr[2], &arr[3], &arr[4], &arr[4]];
let (arr1, _) = refs.split_owned::<1, 5>();
assert_eq!(*arr1[0], 0.);
}
}