#![no_std]
#[macro_export]
macro_rules! const_assert {
($($list:ident : $ty:ty),* => $expr:expr) => {{
struct Assert<$(const $list: usize,)*>;
impl<$(const $list: $ty,)*> Assert<$($list,)*> {
const OK: u8 = 0 - !($expr) as u8;
}
Assert::<$($list,)*>::OK
}};
($expr:expr) => {
const OK: u8 = 0 - !($expr) as u8;
};
}
pub unsafe trait SubArray {
type Item;
fn sub_array_ref<const OFFSET: usize, const M: usize>(&self) -> &[Self::Item; M];
fn sub_array_mut<const OFFSET: usize, const M: usize>(&mut self) -> &mut [Self::Item; M];
}
unsafe impl<T, const N: usize> SubArray for [T; N] {
type Item = T;
#[allow(unsafe_code)]
fn sub_array_ref<const OFFSET: usize, const M: usize>(&self) -> &[Self::Item; M] {
const_assert!(OFFSET: usize, M: usize, N: usize => OFFSET + M <= N);
unsafe { &*(self.as_ptr().add(OFFSET) as *const [T; M]) }
}
#[allow(unsafe_code)]
fn sub_array_mut<const OFFSET: usize, const M: usize>(&mut self) -> &mut [Self::Item; M] {
const_assert!(OFFSET: usize, M: usize, N: usize => OFFSET + M <= N);
unsafe { &mut *(self.as_ptr().add(OFFSET) as *mut [T; M]) }
}
}
unsafe impl<T> SubArray for &mut T
where
T: SubArray,
{
type Item = T::Item;
fn sub_array_ref<const OFFSET: usize, const N: usize>(&self) -> &[Self::Item; N] {
(**self).sub_array_ref::<OFFSET, N>()
}
fn sub_array_mut<const OFFSET: usize, const N: usize>(&mut self) -> &mut [Self::Item; N] {
(**self).sub_array_mut::<OFFSET, N>()
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use alloc::string::String;
use alloc::string::ToString;
use super::*;
#[test]
fn empty_ref() {
let arr = [0_u8; 0];
assert_eq!(arr.sub_array_ref::<0, 0>(), &[]);
}
#[test]
fn empty_mut() {
let mut arr = [0_u8; 0];
assert_eq!(arr.sub_array_mut::<0, 0>(), &mut []);
}
#[test]
fn full_ref() {
let arr = [1, 2, 3_i8];
assert_eq!(arr.sub_array_ref::<0, 3>(), &[1, 2, 3]);
}
#[test]
fn full_mut() {
let mut arr = [1, 2, 3_i8];
assert_eq!(arr.sub_array_mut::<0, 3>(), &mut [1, 2, 3]);
}
#[test]
fn first_ref() {
let arr = [1, 2, 3_u16];
assert_eq!(arr.sub_array_ref::<0, 1>(), &[1]);
}
#[test]
fn first_mut() {
let mut arr = [1, 2, 3_u16];
assert_eq!(arr.sub_array_mut::<0, 1>(), &mut [1]);
}
#[test]
fn middle_ref() {
let arr = [1, 2, 3_i16];
assert_eq!(arr.sub_array_ref::<1, 1>(), &[2]);
}
#[test]
fn middle_mut() {
let mut arr = [1, 2, 3_i16];
assert_eq!(arr.sub_array_mut::<1, 1>(), &mut [2]);
}
#[test]
fn last_ref() {
let arr = [1, 2, 3_i16];
assert_eq!(arr.sub_array_ref::<2, 1>(), &[3]);
}
#[test]
fn last_mut() {
let mut arr = [1, 2, 3_i16];
assert_eq!(arr.sub_array_mut::<2, 1>(), &mut [3]);
}
#[derive(Debug, PartialEq, Eq)]
struct NotClone(&'static str);
const NOT_CLONE_ARRAY: [NotClone; 5] = [
NotClone("abc"),
NotClone("foo"),
NotClone("bar"),
NotClone("qux"),
NotClone("fox"),
];
#[test]
fn not_clone_ref() {
let exp_arr = [NotClone("foo"), NotClone("bar"), NotClone("qux")];
let arr = NOT_CLONE_ARRAY;
assert_eq!(arr.sub_array_ref::<1, 3>(), &exp_arr);
}
#[test]
fn not_clone_mut() {
let mut exp_arr = [NotClone("foo"), NotClone("bar"), NotClone("qux")];
let mut arr = NOT_CLONE_ARRAY;
assert_eq!(arr.sub_array_mut::<1, 3>(), &mut exp_arr);
}
#[test]
fn some_strings() {
let arr: [String; 5] = NOT_CLONE_ARRAY.map(|s| s.0.to_string());
assert_eq!(
arr.sub_array_ref::<2, 2>(),
&[String::from("bar"), String::from("qux")]
);
}
}