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
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
//! Some array extensions that really have no purpose other than to make me feel accomplisheds

#![no_std]
#![allow(incomplete_features)]
#![feature(generic_const_exprs, ptr_metadata)]
#![warn(clippy::pedantic, missing_docs)]

mod slice;
pub use slice::*;

/// Trait that extends upon [array]
pub trait ArrayExt<T, const N: usize>: Sized {
    /// Split an array into two smaller arrays
    ///
    /// ```
    /// use cl_array_ext::ArrayExt;
    /// let (a, b) = [1_i32, 2, 3, 4, 5].array_split_at::<3>();
    /// assert_eq!(a, [1, 2, 3]);
    /// assert_eq!(b, [4, 5]);
    /// ```
    fn array_split_at<const M: usize>(self) -> ([T; M], [T; N - M])
    where
        [T; N - M]: Sized;

    /// Take only M elements out of the array
    ///
    /// ```
    /// use cl_array_ext::ArrayExt;
    /// let a = [1, 2, 3, 4, 5].truncate::<3>();
    /// assert_eq!(a, [1, 2, 3]);
    /// ```
    fn truncate<const M: usize>(self) -> [T; M]
    where
        [T; N - M]: Sized,
    {
        self.array_split_at().0
    }

    /// Join two arrays into one larger array
    ///
    /// ```
    /// use cl_array_ext::ArrayExt;
    /// let a = [1_i32, 2, 3].append([4, 5]);
    /// assert_eq!(a, [1, 2, 3, 4, 5]);
    /// ```
    fn append<const M: usize>(self, other: [T; M]) -> [T; N + M];
}

impl<T, const N: usize> ArrayExt<T, N> for [T; N] {
    fn array_split_at<const M: usize>(self) -> ([T; M], [T; N - M])
    where
        [T; N - M]: Sized,
    {
        let arr = core::mem::ManuallyDrop::new(self).as_ptr();
        unsafe {
            (
                core::ptr::read(arr.add(0).cast()),
                core::ptr::read(arr.add(M).cast()),
            )
        }
    }

    fn append<const M: usize>(self, other: [T; M]) -> [T; N + M] {
        let arr_a = core::mem::ManuallyDrop::new(self).as_ptr();
        let arr_b = core::mem::ManuallyDrop::new(other).as_ptr();
        let mut arr_c = core::mem::MaybeUninit::<[T; N + M]>::uninit();
        let p = arr_c.as_mut_ptr().cast::<T>();

        unsafe {
            core::ptr::copy(arr_a, p.add(0), N);
            core::ptr::copy(arr_b, p.add(N), M);

            core::mem::MaybeUninit::assume_init(arr_c)
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::ArrayExt;

    #[test]
    fn split_at() {
        let (a, b) = [1, 2, 3, 4, 5].array_split_at::<3>();
        assert_eq!(a, [1, 2, 3]);
        assert_eq!(b, [4, 5]);
    }

    #[test]
    fn append() {
        let a = [1, 2, 3].append([4, 5]);

        assert_eq!(a, [1, 2, 3, 4, 5]);
    }
}