#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
#![feature(raw_ref_op)]
#![feature(const_trait_impl)]
#![feature(const_refs_to_cell)]
#![feature(const_ptr_read)]
#![feature(specialization)]
#![cfg_attr(not(test), no_std)]
#![doc = include_str!("../README.md")]
use core::{
mem::{forget, ManuallyDrop},
ptr::{drop_in_place, read},
};
pub trait ArrayAdd<T, const N: usize>: Sized {
fn append(self, e: T) -> [T; N + 1];
fn append_back(self, e: T) -> [T; N + 1];
fn concat<const L: usize>(self, array: [T; L]) -> [T; N + L];
fn concat_back<const L: usize>(self, array: [T; L]) -> [T; N + L];
}
pub trait ArrayRemove<T, const N: usize>: Sized {
fn truncate_start<const L: usize>(self) -> [T; N - L];
fn truncate_end<const L: usize>(self) -> [T; N - L];
}
#[repr(C)]
struct Contiguous<A, B>(A, B);
const unsafe fn transmute_unchecked<From, To>(from: From) -> To {
union Transmute<From, To> {
from: ManuallyDrop<From>,
to: ManuallyDrop<To>,
}
ManuallyDrop::into_inner(
Transmute {
from: ManuallyDrop::new(from),
}
.to,
)
}
impl<T, const N: usize> const ArrayAdd<T, N> for [T; N] {
fn concat<const L: usize>(self, array: [T; L]) -> [T; N + L] {
unsafe {
transmute_unchecked(Contiguous(self, array))
}
}
fn concat_back<const L: usize>(self, array: [T; L]) -> [T; N + L] {
unsafe {
transmute_unchecked(Contiguous(array, self))
}
}
fn append(self, element: T) -> [T; N + 1] {
unsafe {
transmute_unchecked(Contiguous(self, element))
}
}
fn append_back(self, element: T) -> [T; N + 1] {
unsafe {
transmute_unchecked(Contiguous(element, self))
}
}
}
impl<T, const N: usize> ArrayRemove<T, N> for [T; N] {
default fn truncate_start<const L: usize>(mut self) -> [T; N - L] {
unsafe {
let result = read((&raw const self).cast::<T>().add(L).cast()); drop_in_place(&raw mut self[..L]); forget(self); result
}
}
default fn truncate_end<const L: usize>(mut self) -> [T; N - L] {
unsafe {
drop_in_place(&raw mut self[L..]); transmute_unchecked(self) }
}
}
impl<T: Copy, const N: usize> const ArrayRemove<T, N> for [T; N] {
fn truncate_start<const L: usize>(self) -> [T; N - L] {
unsafe {
read((&raw const self).cast::<T>().add(L).cast()) }
}
fn truncate_end<const L: usize>(self) -> [T; N - L] {
unsafe {
transmute_unchecked(self) }
}
}
#[cfg(test)]
mod tests {
use crate::{ArrayAdd, ArrayRemove};
#[test]
fn append_noncopy() {
let input = [vec![1, 2], vec![3, 4]];
let expected = [vec![1, 2], vec![3, 4], vec![5, 6, 7]];
let result = input.append(vec![5, 6, 7]);
assert_eq!(expected, result)
}
#[test]
fn append_back_noncopy() {
let input = [vec![1, 2], vec![3, 4]];
let expected = [vec![254, 255, 0], vec![1, 2], vec![3, 4]];
let result = input.append_back(vec![254, 255, 0]);
assert_eq!(expected, result)
}
#[test]
fn concat_noncopy() {
let input = [vec![1, 2], vec![3, 4]];
let expected = [
vec![1, 2],
vec![3, 4],
vec![5, 6, 7],
vec![8, 9],
vec![10, 11, 12],
];
let result = input.concat([vec![5, 6, 7], vec![8, 9], vec![10, 11, 12]]);
assert_eq!(expected, result)
}
#[test]
fn concat_back_noncopy() {
let input = [vec![1, 2], vec![3, 4]];
let expected = [
vec![249, 250, 251],
vec![252, 253],
vec![254, 255, 0],
vec![1, 2],
vec![3, 4],
];
let result = input.concat_back([vec![249, 250, 251], vec![252, 253], vec![254, 255, 0]]);
assert_eq!(expected, result)
}
#[test]
fn truncate_start_noncopy() {
let input = [vec![1, 2], vec![3, 4], vec![5, 6], vec![7, 8]];
let expected = [vec![5, 6], vec![7, 8]];
let result = input.truncate_start::<2>();
assert_eq!(expected, result)
}
#[test]
fn truncate_end_noncopy() {
let input = [vec![1, 2], vec![3, 4], vec![5, 6], vec![7, 8]];
let expected = [vec![1, 2], vec![3, 4]];
let result = input.truncate_end::<2>();
assert_eq!(expected, result)
}
#[test]
fn append_copy() {
let input = [1, 2, 3, 4];
let expected = [1, 2, 3, 4, 5];
let result = input.append(5);
assert_eq!(expected, result)
}
#[test]
fn append_back_copy() {
let input = [1, 2, 3, 4];
let expected = [0, 1, 2, 3, 4];
let result = input.append_back(0);
assert_eq!(expected, result)
}
#[test]
fn concat_copy() {
let input = [1, 2, 3, 4];
let expected = [1, 2, 3, 4, 5, 6, 7];
let result = input.concat([5, 6, 7]);
assert_eq!(expected, result)
}
#[test]
fn concat_back_copy() {
let input = [1, 2, 3, 4];
let expected = [254, 255, 0, 1, 2, 3, 4];
let result = input.concat_back([254, 255, 0]);
assert_eq!(expected, result)
}
#[test]
fn truncate_start_copy() {
let input = [1, 2, 3, 4];
let expected = [3, 4];
let result = input.truncate_start::<2>();
assert_eq!(expected, result)
}
#[test]
fn truncate_end_copy() {
let input = [1, 2, 3, 4];
let expected = [1, 2];
let result = input.truncate_end::<2>();
assert_eq!(expected, result)
}
}