blob: 0f1e6dd02ba984e85d6a2c1bc0ed4554a3a009f9 [file] [log] [blame]
//! Safe wrappers for memory-accessing functions like `std::ptr::copy()`.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate core as std;
use std::ptr;
macro_rules! idx_check (
($slice:expr, $idx:expr) => {
assert!($idx < $slice.len(),
concat!("`", stringify!($idx), "` ({}) out of bounds. Length: {}"),
$idx, $slice.len());
}
);
macro_rules! len_check (
($slice:expr, $start:ident, $len:ident) => {
assert!(
$start.checked_add($len)
.expect(concat!("Overflow evaluating ", stringify!($start + $len)))
<= $slice.len(),
"Length {} starting at {} is out of bounds (slice len {}).", $len, $start, $slice.len()
)
}
);
/// Copy `len` elements from `src_idx` to `dest_idx`. Ranges may overlap.
///
/// Safe wrapper for `memmove()`/`std::ptr::copy()`.
///
/// ###Panics
/// * If either `src_idx` or `dest_idx` are out of bounds, or if either of these plus `len` is out of
/// bounds.
/// * If `src_idx + len` or `dest_idx + len` overflows.
pub fn copy_over<T: Copy>(slice: &mut [T], src_idx: usize, dest_idx: usize, len: usize) {
if slice.len() == 0 { return; }
idx_check!(slice, src_idx);
idx_check!(slice, dest_idx);
len_check!(slice, src_idx, len);
len_check!(slice, dest_idx, len);
let src_ptr: *const T = &slice[src_idx];
let dest_ptr: *mut T = &mut slice[dest_idx];
unsafe {
ptr::copy(src_ptr, dest_ptr, len);
}
}
/// Safe wrapper for `std::ptr::write_bytes()`/`memset()`.
pub fn write_bytes(slice: &mut [u8], byte: u8) {
unsafe {
ptr::write_bytes(slice.as_mut_ptr(), byte, slice.len());
}
}
/// Prepend `elems` to `vec`, resizing if necessary.
///
/// ###Panics
/// If `vec.len() + elems.len()` overflows.
#[cfg(feature = "std")]
pub fn prepend<T: Copy>(elems: &[T], vec: &mut Vec<T>) {
// Our overflow check occurs here, no need to do it ourselves.
vec.reserve(elems.len());
let old_len = vec.len();
let new_len = old_len + elems.len();
unsafe {
vec.set_len(new_len);
}
// Move the old elements down to the end.
if old_len > 0 {
copy_over(vec, 0, elems.len(), old_len);
}
vec[..elems.len()].copy_from_slice(elems);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn bounds_check() {
let mut arr = [0i32, 1, 2, 3, 4, 5];
copy_over(&mut arr, 2, 1, 7);
}
#[test]
fn copy_empty() {
let mut arr: [i32; 0] = [];
copy_over(&mut arr, 0, 0, 0);
}
#[test]
#[cfg(feature = "std")]
fn prepend_empty() {
let mut vec: Vec<i32> = vec![];
prepend(&[1, 2, 3], &mut vec);
}
#[test]
#[cfg(feature = "std")]
fn prepend_i32() {
let mut vec = vec![3, 4, 5];
prepend(&[1, 2], &mut vec);
assert_eq!(vec, &[1, 2, 3, 4, 5]);
}
}