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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
#![feature(raw_ref_op)]
#![no_std]
#![doc = include_str!("../README.md")]
use core::{
mem::{forget, zeroed},
ptr::{copy_nonoverlapping, drop_in_place},
};
/// Holds the methods for manipulating arrays in a Vec-like fashion.
/// Will (probably) get into core when
/// [generic-const-exprs](https://doc.rust-lang.org/beta/unstable-book/language-features/generic-const-exprs.html)
/// becomes complete.
pub trait ArrayManipulation<T, const N: usize>: Sized {
/// Takes an array of L elements and appends it at the end of Self.
/// Performs 2 calls to `memcpy()`, so if your code heavily uses it
/// maybe a linked list is a better fit for your use case.
/// # Examples
/// ```
/// use array_manipulation::ArrayManipulation;
///
/// let array: [u8; 4] = [1, 2, 3, 4];
/// let expected = [1, 2, 3, 4, 5, 6, 7];
/// let result = array.push([5, 6, 7]);
/// assert_eq!(expected, result);
/// ```
fn push<const L: usize>(self, array: [T; L]) -> [T; N + L];
/// Takes an array of L elements and appends it at the start of Self.
/// Performs 2 calls to `memcpy()`, so if your code heavily uses it
/// maybe a linked list is a better fit for your use case.
/// # Examples
/// ```
/// use array_manipulation::ArrayManipulation;
///
/// let array: [u8; 4] = [1, 2, 3, 4];
/// let expected = [0, 1, 2, 3, 4];
/// let result = array.push_back([0]);
/// assert_eq!(expected, result);
/// ```
fn push_back<const L: usize>(self, array: [T; L]) -> [T; N + L];
/// `memcpy()`s all the elements on an array except the last one.
/// Basically it creates a new fixed-size array with all the
/// elements except the last one. Won't compile if N == 0.
/// # Examples
/// ```
/// use array_manipulation::ArrayManipulation;
///
/// let array: [u8; 4] = [1, 2, 3, 4];
/// let expected = [1, 2, 3];
/// let result = array.pop();
/// assert_eq!(expected, result);
/// ```
fn pop(self) -> [T; N - 1];
/// `memcpy()`s all the elements on an array except the first one.
/// Basically it creates a new fixed-size array with all the
/// elements except the first one. Won't compile if N == 0.
/// # Examples
/// ```
/// use array_manipulation::ArrayManipulation;
///
/// let array: [u8; 4] = [1, 2, 3, 4];
/// let expected = [2, 3, 4];
/// let result = array.pop_back();
/// assert_eq!(expected, result);
/// ```
fn pop_back(self) -> [T; N - 1];
}
impl<T, const N: usize> ArrayManipulation<T, N> for [T; N] {
fn push<const L: usize>(self, array: [T; L]) -> [T; N + L] {
unsafe {
let mut result: [T; N + L] = zeroed(); // no real need to use MaybeUninit
let dst = &raw mut result; // get ptr
copy_nonoverlapping(&raw const self, dst.cast(), 1); // copy elements
let dst = &raw mut result[N..]; // offset ptr by N
copy_nonoverlapping(&raw const array, dst.cast(), 1); // copy elements
// avoid drop & deallocation of the copied elements
forget(self);
forget(array);
result
}
}
fn push_back<const L: usize>(self, array: [T; L]) -> [T; N + L] {
unsafe {
let mut result: [T; N + L] = zeroed(); // no real need to use MaybeUninit
let dst = &raw mut result; // get ptr
copy_nonoverlapping(&raw const array, dst.cast(), 1); // copy elements
let dst = &raw mut result[L..]; // offset ptr by L
copy_nonoverlapping(&raw const self, dst.cast(), 1); // copy elements
// avoid drop & deallocation of the copied elements
forget(self);
forget(array);
result
}
}
fn pop(mut self) -> [T; N - 1] {
unsafe {
let mut result: [T; N - 1] = zeroed(); // no real need to use MaybeUninit
let src = &raw const self; // get ptr
copy_nonoverlapping(src.cast(), &raw mut result, 1); // copy elements
drop_in_place(&raw mut self[N - 1]); // drop popped element
forget(self); // avoid drop & deallocation of the copied elements
result
}
}
fn pop_back(mut self) -> [T; N - 1] {
unsafe {
let mut result: [T; N - 1] = zeroed(); // no real need to use MaybeUninit
let src = &raw const self[1..]; // offset ptr by size_of::<T>()
copy_nonoverlapping(src.cast(), &raw mut result, 1); // copy elements
drop_in_place(&raw mut self[0]); // drop popped element
forget(self); // avoid drop & deallocation of the copied elements
result
}
}
}