//! Extensions use super::*; use std::{ marker::PhantomData, fmt, ops, }; /// Wrapper to derive debug for types that don't implement it. #[repr(transparent)] #[derive(Clone, PartialEq, Eq, Ord,PartialOrd, Hash)] pub struct OpaqueDebug(T); impl OpaqueDebug { /// Create a new wrapper #[inline] pub const fn new(value: T) -> Self { Self(value) } /// Consume into the value #[inline] pub fn into_inner(self) -> T { self.0 } } impl AsRef for OpaqueDebug { #[inline] fn as_ref(&self) -> &T { &self.0 } } impl AsMut for OpaqueDebug { #[inline] fn as_mut(&mut self) -> &mut T { &mut self.0 } } impl ops::Deref for OpaqueDebug { type Target = T; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl ops::DerefMut for OpaqueDebug { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl fmt::Debug for OpaqueDebug { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "") } } /// A trait for types that can insert objects at their end. pub trait BackInserter { /// Insert an object at the end of this container fn push_back(&mut self, value: T); } impl BackInserter for Vec { #[inline] fn push_back(&mut self, value: T) { self.push(value) } } /// Absracts a closure for `BackInserter`. pub struct BackInsertPass(F, PhantomData) where F: FnMut(T); impl BackInsertPass { /// Create a new instance with this closure #[inline] pub fn new(func: F) -> Self { Self(func, PhantomData) } } impl BackInserter for BackInsertPass { #[inline] fn push_back(&mut self, value: T) { self.0(value) } } /// A `BackInserter` that will only add a max capacity of items before it starts dropping input to its `push_back` function. pub struct CappedBackInserter<'a, T>(&'a mut T, usize, usize) where T: BackInserter; impl<'a, T> CappedBackInserter<'a, T> where T: BackInserter { /// Create a new instance with this max capacity #[inline] pub fn new(from: &'a mut T, cap: usize) -> Self { Self(from, 0, cap) } /// The number of elements pushed so far #[inline] pub fn len(&self) -> usize { self.1 } /// The max number of elemnts allowed to be pushed #[inline] pub fn cap(&self) -> usize { self.2 } } impl<'a, T> BackInserter for CappedBackInserter<'a, T> where T: BackInserter { #[inline] fn push_back(&mut self, value: T) { if self.1 < self.2 { self.0.push_back(value); self.1+=1; } } } pub trait VecExt { /// Insert many elements with exact size iterator fn insert_exact>(&mut self, location: usize, slice: I) where Ex: ExactSizeIterator; /// Insert many elements fn insert_many>(&mut self, location: usize, slice: I); } impl VecExt for Vec { #[cfg(not(feature="experimental_inserter"))] #[inline(always)] fn insert_exact>(&mut self, location: usize, slice: I) where Ex: ExactSizeIterator { self.insert_many(location, slice) } #[cfg(feature="experimental_inserter")] fn insert_exact>(&mut self, location: usize, slice: I) where Ex: ExactSizeIterator, { #[inline(never)] #[cold] fn panic_len(l1: usize, l2: usize) -> ! { panic!("Location must be in range 0..{}, got {}", l1,l2) } #[inline(never)] #[cold] fn inv_sz() -> ! { panic!("ExactSizeIterator returned invalid size"); } if location >= self.len() { panic_len(self.len(), location); } let mut slice = slice.into_iter(); let slen = slice.len(); match slen { 0 => return, 1 => { self.insert(location, slice.next().unwrap()); return }, _ => (), }; self.reserve(slice.len()); unsafe { let this = self.as_mut_ptr().add(location); let len = self.len(); let rest = std::mem::size_of::() * (location..len).len(); libc::memmove(this.add(slen) as *mut libc::c_void, this as *mut libc::c_void, rest); let mut sent=0; match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { let mut this = this; for item in slice { if sent >= slen { inv_sz(); } this.write(item); this = this.add(1); sent+=1; } if sent != slen { inv_sz(); } })) { Err(e) => { // memory at (location+sent)..slen is now invalid, move the old one back before allowing unwind to contine libc::memmove(this.add(sent) as *mut libc::c_void, this.add(slen) as *mut libc::c_void, rest); self.set_len(len + sent); std::panic::resume_unwind(e) }, _ => (), } self.set_len(len + sent); } } #[inline] fn insert_many>(&mut self, location: usize, slice: I) { let slice = slice.into_iter(); match slice.size_hint() { (0, Some(0)) | (0, None) => (), (_, Some(bound)) | (bound, _) => self.reserve(bound), }; self.splice(location..location, slice); //let splice = self.split_off(location); //self.extend(slice.chain(splice.into_iter())); /* // shift everything across, replacing with the new values let splice: Vec<_> = self.splice(location.., slice).collect(); // ^ -- this allocation bugs me, but we violate aliasing rules if we don't somehow collect it before adding it back in so... // add tail back self.extend(splice);*/ } } #[cfg(test)] mod tests { use super::*; #[test] fn vec_insert_exact() { let mut vec = vec![0,1,2,8,9,10]; vec.insert_exact(3, [3,4,5,6, 7].iter().copied()); assert_eq!(&vec[..], &[0,1,2,3,4,5,6,7,8,9,10] ); } #[test] fn vec_insert_exact_nt() { macro_rules! string { ($str:literal) => (String::from($str)); } let mut vec = vec![ string!("Hello"), string!("world"), string!("foo"), string!("uhh"), ]; let vec2 = vec![ string!("Hello"), string!("world"), string!("hi"), string!("hello"), string!("foo"), string!("uhh"), ]; vec.insert_exact(2, vec![string!("hi"), string!("hello")]); assert_eq!(&vec[..], &vec2[..]); } #[cfg(nightly)] mod benchmatks { use super::super::*; use test::{ Bencher, black_box, }; #[cfg(not(feature="experimental_inserter"))] #[bench] fn move_exact(b: &mut Bencher) { let mut vec = vec![0,10,11,12]; let span = [0,1,2,3]; b.iter(|| { black_box(vec.insert_exact(vec.len()/2, span.iter().copied())); }); } #[bench] fn move_via_splice(b: &mut Bencher) { let mut vec = vec![0,10,11,12]; let span = [0,1,2,3]; b.iter(|| { black_box(vec.insert_many(vec.len()/2, span.iter().copied())); }); } #[cfg(feature="experimental_inserter")] #[bench] fn move_via_unsafe(b: &mut Bencher) { let mut vec = vec![0,10,11,12]; let span = [0,1,2,3]; b.iter(|| { black_box(vec.insert_exact(vec.len()/2, span.iter().copied())); }); } } }