Skip to main content

lexe_std/
array.rs

1//! Small helper functions for arrays.
2
3/// `const` concatenate two arrays.
4pub const fn concat<T: Copy, const N: usize, const M: usize, const O: usize>(
5    first: [T; N],
6    second: [T; M],
7) -> [T; O] {
8    assert!(O == N + M);
9    crate::const_utils::const_concat_inner(&[&first, &second])
10}
11
12/// `const` pad an `M`-byte array with zeroes, so that it's `N` bytes long.
13// TODO(phlip9): should be an extension trait method, but rust doesn't allow
14// const trait fns yet.
15pub const fn pad<const N: usize, const M: usize>(input: [u8; M]) -> [u8; N] {
16    assert!(N >= M);
17
18    let mut out = [0u8; N];
19    let mut idx = 0;
20    loop {
21        if idx >= M {
22            break;
23        }
24        out[idx] = input[idx];
25        idx += 1;
26    }
27    out
28}
29
30/// Copies of nightly-only functions for `[u8; N]`.
31// TODO(phlip9): remove functions as they stabilize.
32pub trait ArrayExt<const N: usize> {
33    /// Divides one array reference into two at an index.
34    ///
35    /// The first will contain all indices from `[0, M)` (excluding
36    /// the index `M` itself) and the second will contain all
37    /// indices from `[M, N)` (excluding the index `N` itself).
38    fn split_array_ref_stable<const M: usize>(&self) -> (&[u8; M], &[u8]);
39
40    /// Divides one array reference into two at an index from the end.
41    ///
42    /// The first will contain all indices from `[0, N - M)` (excluding
43    /// the index `N - M` itself) and the second will contain all
44    /// indices from `[N - M, N)` (excluding the index `N` itself).
45    fn rsplit_array_ref_stable<const M: usize>(&self) -> (&[u8], &[u8; M]);
46}
47
48impl<const N: usize> ArrayExt<N> for [u8; N] {
49    #[inline]
50    fn split_array_ref_stable<const M: usize>(&self) -> (&[u8; M], &[u8]) {
51        self[..].split_first_chunk::<M>().unwrap()
52    }
53
54    #[inline]
55    fn rsplit_array_ref_stable<const M: usize>(&self) -> (&[u8], &[u8; M]) {
56        self[..].split_last_chunk::<M>().unwrap()
57    }
58}
59
60#[cfg(test)]
61mod test {
62    use crate::array;
63
64    #[test]
65    fn test_concat() {
66        const ACTUAL: [&str; 3] = array::concat(["a"], ["b", "c"]);
67        assert_eq!(ACTUAL, ["a", "b", "c"]);
68
69        const EMPTY: [&str; 0] = [];
70        const ACTUAL_WITH_EMPTY: [&str; 3] = array::concat(EMPTY, ACTUAL);
71        assert_eq!(ACTUAL_WITH_EMPTY, ACTUAL);
72    }
73
74    #[test]
75    fn test_pad() {
76        let input = *b"hello";
77        let actual = array::pad(input);
78        let expected = *b"hello\x00\x00\x00\x00\x00";
79        assert_eq!(actual, expected);
80
81        let actual = array::pad(input);
82        let expected = *b"hello";
83        assert_eq!(actual, expected);
84    }
85}