#[doc(hidden)]
pub mod reexport {
#[inline] pub fn clone<T: Clone>(source: T) -> T { source.clone() }
#[inline] pub unsafe fn ptr_write<T>(dst: *mut T, src: T) { ::std::ptr::write(dst, src) }
#[inline] pub unsafe fn ptr_read<T>(src: *const T) -> T { ::std::ptr::read(src) }
#[inline] pub fn forget<T>(t: T) { ::std::mem::forget(t) }
#[inline] pub unsafe fn uninitialized<T>() -> T { ::std::mem::uninitialized() }
}
#[cfg(feature="use_std")]
#[macro_export]
#[doc(hidden)]
macro_rules! slice_as_array_transmute {
($slice:expr) => { ::std::mem::transmute($slice) }
}
#[cfg(not(feature="use_std"))]
#[macro_export]
macro_rules! slice_as_array_transmute {
($slice:expr) => { ::core::mem::transmute($slice) }
}
#[macro_export]
macro_rules! slice_as_array {
($slice:expr, [$t:ty ; $len:expr] ) => {{
unsafe fn this_transmute(xs: &[$t]) -> &[$t; $len] {
slice_as_array_transmute!(xs.as_ptr())
}
let s: &[$t] = $slice;
if s.len() == $len {
Some( unsafe { this_transmute(s) } )
} else {
None
}
}}
}
#[macro_export]
macro_rules! slice_as_array_mut {
($slice:expr, [$t:ty ; $len:expr] ) => {{
unsafe fn this_transmute(xs: &mut [$t]) -> &mut [$t; $len] {
slice_as_array_transmute!(xs.as_mut_ptr())
}
let s: &mut [$t] = $slice;
if s.len() == $len {
Some( unsafe { this_transmute(s) } )
} else {
None
}
}}
}
#[macro_export]
macro_rules! slice_to_array_clone {
($slice:expr, [$t:ty ; $len:expr] ) => {{
struct SafeArrayInitialization {
array: Option<[$t; $len]>,
count: usize,
}
impl SafeArrayInitialization {
fn new() -> Self {
SafeArrayInitialization { array: Some(unsafe { $crate::reexport::uninitialized() }), count: 0 }
}
fn init_from_slice(mut self, slice: &[$t]) -> Option<[$t; $len]> {
{
let array_mut: &mut [$t] = self.array.as_mut().unwrap().as_mut();
if slice.len() != array_mut.len() {
return None;
}
debug_assert_eq!(self.count, 0);
for (val, ptr) in slice.iter().zip(array_mut.iter_mut()) {
let val = $crate::reexport::clone(*val);
unsafe { $crate::reexport::ptr_write(ptr, val) };
self.count += 1;
}
}
self.array.take()
}
}
impl Drop for SafeArrayInitialization {
fn drop(&mut self) {
if let Some(mut array) = self.array.take() {
let count = self.count;
{
for ptr in array.as_mut()[..count].iter_mut() {
unsafe { $crate::reexport::ptr_read(ptr) };
}
}
$crate::reexport::forget(array);
}
}
}
SafeArrayInitialization::new().init_from_slice($slice)
}}
}
#[cfg(test)]
mod test {
#[test]
fn correct_length() {
let xs: [u32; 6] = [1, 2, 4, 8, 16, 32];
let xs_prefix: &[u32; 3] = slice_as_array!(&xs[1..4], [u32; 3]).expect("Length mismatch");
assert_eq!(xs_prefix, &[2, 4, 8]);
}
#[test]
fn incorrect_length() {
let xs: [u32; 6] = [1, 2, 4, 8, 16, 32];
let xs_prefix: Option<&[u32; 8]> = slice_as_array!(&xs[1..4], [u32; 8]);
assert_eq!(xs_prefix, None);
}
#[test]
#[should_panic]
fn overlong_length() {
let xs: [u32; 6] = [1, 2, 4, 8, 16, 32];
let xs_prefix: Option<&[u32; 8]> = slice_as_array!(&xs[0..8], [u32; 8]);
assert_eq!(xs_prefix, None);
}
#[test]
fn zero_length() {
let xs: [u32; 6] = [1, 2, 4, 8, 16, 32];
let xs_prefix: &[u32; 0] = slice_as_array!(&xs[1..1], [u32; 0]).unwrap();
assert_eq!(xs_prefix, &[]);
}
#[test]
fn array_of_arrays() {
let xs: [[u8; 4]; 3] = [
[10,11,12,13],
[20,21,22,23],
[30,31,32,33],
];
let xs_suffix: &[[u8;4]; 2] = slice_as_array!(&xs[1..], [[u8; 4]; 2]).unwrap();
assert_eq!(xs_suffix[0][0], 20);
assert_eq!(xs_suffix[1][3], 33);
}
#[test]
fn clone_correct() {
let xs: [u32; 6] = [1, 2, 4, 8, 16, 32];
let xs_middle: [u32; 3] = slice_to_array_clone!(&xs[1..4], [u32; 3]).expect("Length mismatch");
assert_eq!(xs_middle, [2, 4, 8]);
}
#[test]
fn clone_wrong_length() {
let xs: [u32; 6] = [1, 2, 4, 8, 16, 32];
let xs_middle: Option<[u32; 3]> = slice_to_array_clone!(&xs[1..5], [u32; 3]);
assert_eq!(xs_middle, None);
}
}