#[cfg(feature = "unsafe_fast_code")]
pub use self::usafe::{ drop_n, drain_n, drain_into };
#[cfg(not(feature = "unsafe_fast_code"))]
pub use self::safe::{ drop_n, drain_n, drain_into };
#[cfg(feature = "unsafe_fast_code")]
mod usafe {
use std::{ ptr, mem };
unsafe fn drop_in_place<T>(slice: &mut[T]) {
if mem::needs_drop::<T>() {
let mut ptr = slice.as_mut_ptr();
(0..slice.len()).for_each(|_| {
ptr.drop_in_place();
ptr = ptr.offset(1);
})
}
}
unsafe fn discard_n<T>(vec: &mut Vec<T>, n: usize) {
assert!(n <= vec.len(), "`n` is greater than `vec.len()`");
let remaining = vec.len() - n;
ptr::copy(vec[n..].as_ptr(), vec.as_mut_ptr(), remaining);
vec.set_len(remaining);
}
pub fn drop_n<T>(vec: &mut Vec<T>, n: usize) {
assert!(n <= vec.len(), "`n` is greater than `vec.len()`");
unsafe{ drop_in_place(&mut vec[..n]) }
unsafe{ discard_n(vec, n) }
}
pub fn drain_n<T>(src: &mut Vec<T>, n: usize) -> Vec<T> {
assert!(n <= src.len(), "`n` is greater than `src.len()`");
let mut dst = Vec::with_capacity(n);
unsafe{ dst.set_len(n) }
unsafe{ ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), n) }
unsafe{ discard_n(src, n) }
dst
}
pub fn drain_into<T>(src: &mut Vec<T>, dst: &mut[T]) {
assert!(dst.len() <= src.len());
unsafe{ drop_in_place(dst) }
unsafe{ ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), dst.len()) }
unsafe{ discard_n(src, dst.len()) }
}
}
#[cfg(not(feature = "unsafe_fast_code"))]
mod safe {
pub fn drop_n<T>(src: &mut Vec<T>, n: usize) {
src.drain(..n);
}
pub fn drain_n<T>(src: &mut Vec<T>, n: usize) -> Vec<T> {
src.drain(..n).collect()
}
pub fn drain_into<T>(src: &mut Vec<T>, dst: &mut[T]) {
let (mut src, dst) = (src.drain(..dst.len()), dst.iter_mut());
dst.for_each(|t| *t = src.next().unwrap());
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use super::{ drop_n, drain_n, drain_into };
fn rc_vec(n: usize) -> Vec<Rc<usize>> {
let mut vec = Vec::new();
(0..n).for_each(|i| vec.push(Rc::new(i)));
vec
}
#[test]
fn test_drop_n() {
let base = rc_vec(42);
let mut cloned = base.clone();
base.iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 2));
drop_n(&mut cloned, 7);
assert_eq!(cloned.len(), base.len() - 7);
base[..7].iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 1));
base[7..].iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 2));
}
#[test]
fn test_drain_n() {
let base = rc_vec(42);
let mut cloned = base.clone();
base.iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 2));
let drained = drain_n(&mut cloned, 7);
assert_eq!(drained.len(), 7);
assert_eq!(cloned.len(), base.len() - 7);
(0..7).for_each(|i| assert_eq!(*drained[i], i));
(7..base.len()).for_each(|i| assert_eq!(*cloned[i - 7], i));
base.iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 2));
}
#[test]
fn test_drain_into() {
let src_base = rc_vec(42);
let dst_base = rc_vec(7);
let mut src = src_base.clone();
let mut dst = dst_base.clone();
src_base.iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 2));
dst_base.iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 2));
drain_into(&mut src, &mut dst);
assert_eq!(dst.len(), dst_base.len());
assert_eq!(src.len(), src_base.len() - 7);
(0..dst_base.len()).for_each(|i| assert_eq!(*dst[i], i));
(dst_base.len()..src_base.len()).for_each(|i| assert_eq!(*src[i - 7], i));
src_base.iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 2));
dst_base.iter().for_each(|rc| assert_eq!(Rc::strong_count(rc), 1));
}
}