#![deny(missing_docs)]
#![cfg_attr(not(test), no_std)]
extern crate alloc;
use alloc::vec::Vec;
use core::{mem::ManuallyDrop, ptr};
pub struct Removing<'a, T> {
vec: &'a mut Vec<T>,
slot: usize,
curr: usize,
len: usize,
}
impl<'a, T> Removing<'a, T> {
#[inline]
pub fn new(vec: &'a mut Vec<T>) -> Self {
let len = vec.len();
unsafe {
vec.set_len(0);
}
Self {
vec,
slot: 0,
curr: 0,
len,
}
}
#[inline]
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Option<Entry<'_, 'a, T>> {
if self.is_empty() {
None
} else {
Some(Entry { rem: self })
}
}
pub fn len(&self) -> usize {
self.len - self.curr
}
#[inline]
pub fn is_empty(&self) -> bool {
self.curr == self.len
}
unsafe fn ptr_mut(&mut self, offset: usize) -> *mut T {
self.vec.as_mut_ptr().add(offset)
}
fn slot_mut(&mut self) -> *mut T {
unsafe { self.ptr_mut(self.slot) }
}
fn curr_mut(&mut self) -> *mut T {
unsafe { self.ptr_mut(self.curr) }
}
}
impl<T> Drop for Removing<'_, T> {
fn drop(&mut self) {
unsafe {
let len = self.len();
if len != 0 {
ptr::copy(self.curr_mut(), self.slot_mut(), len);
}
self.vec.set_len(self.slot + len)
}
}
}
pub struct Entry<'a, 'rem, T> {
rem: &'a mut Removing<'rem, T>,
}
impl<T> Entry<'_, '_, T> {
#[inline]
pub fn remove(self) -> T {
let mut this = ManuallyDrop::new(self);
unsafe {
let curr = this.curr_mut();
this.rem.curr += 1;
ptr::read(curr)
}
}
#[inline]
pub fn value(&self) -> &T {
unsafe {
&*self.curr_ptr()
}
}
#[inline]
pub fn value_mut(&mut self) -> &mut T {
unsafe {
&mut *self.curr_mut()
}
}
#[inline]
pub fn peek_next(&mut self) -> Option<&mut T> {
let next = self.rem.curr + 1;
if next >= self.rem.len {
return None;
}
unsafe {
Some(&mut *self.rem.ptr_mut(next))
}
}
fn curr_mut(&mut self) -> *mut T {
self.rem.curr_mut()
}
fn curr_ptr(&self) -> *const T {
unsafe { self.rem.vec.as_ptr().add(self.rem.curr) }
}
fn slot_mut(&mut self) -> *mut T {
self.rem.slot_mut()
}
}
impl<T> Drop for Entry<'_, '_, T> {
fn drop(&mut self) {
unsafe {
ptr::copy(self.curr_mut(), self.slot_mut(), 1);
self.rem.slot += 1;
self.rem.curr += 1;
}
}
}
pub trait VecExt<T> {
fn removing(&mut self) -> Removing<T>;
}
impl<T> VecExt<T> for Vec<T> {
#[inline]
fn removing(&mut self) -> Removing<T> {
Removing::new(self)
}
}
#[cfg(test)]
mod tests {
use crate::VecExt;
use core::{fmt::Debug, mem, ops::Rem};
fn f(i: i32) -> impl Clone + Debug + Eq + PartialOrd<i32> + Rem<i32, Output = i32> {
#[derive(Clone, Debug, PartialEq, Eq)]
struct NoCopy(i32);
impl PartialEq<i32> for NoCopy {
fn eq(&self, other: &i32) -> bool {
self.0.eq(other)
}
}
impl PartialOrd<i32> for NoCopy {
fn partial_cmp(&self, other: &i32) -> Option<core::cmp::Ordering> {
self.0.partial_cmp(other)
}
}
impl Rem<i32> for NoCopy {
type Output = i32;
fn rem(self, rem: i32) -> i32 {
self.0 % rem
}
}
NoCopy(i)
}
fn zf(_i: i32) -> impl Debug + Eq {
#[derive(Debug, PartialEq, Eq)]
struct No;
No
}
#[test]
fn clear() {
let mut vec: Vec<_> = (0..10).map(f).collect();
let mut out = Vec::with_capacity(10);
let mut rem = vec.removing();
while let Some(entry) = rem.next() {
out.push(entry.remove());
}
assert_eq!(out, (0..10).map(f).collect::<Vec<_>>())
}
#[test]
fn skip() {
let mut vec: Vec<_> = (0..10).map(f).collect();
let mut rem = vec.removing();
while let Some(_entry) = rem.next() {}
}
#[test]
fn forget_entry() {
let mut vec = vec![f(0)];
{
let mut rem = vec.removing();
let mut timeout = 0..100;
while let (Some(entry), Some(_)) = (rem.next(), timeout.next()) {
mem::forget(entry)
}
assert_eq!(timeout.len(), 0);
}
assert_eq!(vec, [f(0)]);
}
#[test]
fn zforget_entry() {
let mut vec = vec![zf(0)];
{
let mut rem = vec.removing();
let mut timeout = 0..100;
while let (Some(entry), Some(_)) = (rem.next(), timeout.next()) {
mem::forget(entry)
}
assert_eq!(timeout.len(), 0);
}
assert_eq!(vec, [zf(0)]);
}
#[test]
#[cfg(not(miri))]
fn forget() {
let mut vec: Vec<_> = (0..10).map(f).collect();
let mut rem = vec.removing();
if let Some(entry) = rem.next() {
entry.remove();
}
if let Some(entry) = rem.next() {
entry.remove();
}
if let Some(entry) = rem.next() {
entry.remove();
}
mem::forget(rem);
assert_eq!(vec, [0; 0]);
}
#[test]
fn drop() {
let mut vec: Vec<_> = (0..10).map(f).collect();
mem::drop(vec.removing());
assert_eq!(vec, (0..10).map(f).collect::<Vec<_>>());
}
#[test]
fn even() {
let mut vec: Vec<_> = (0..10).map(f).collect();
let mut out = Vec::with_capacity(10);
let mut rem = vec.removing();
while let Some(entry) = rem.next() {
if entry.value().clone() % 2 == 0 {
out.push(entry.remove());
}
}
mem::drop(rem);
assert_eq!(out, [0, 2, 4, 6, 8]);
assert_eq!(vec, [1, 3, 5, 7, 9]);
}
#[test]
fn break_() {
let mut vec: Vec<_> = (0..10).map(f).collect();
let mut rem = vec.removing();
while let Some(entry) = rem.next() {
if *entry.value() >= 5 {
break;
}
entry.remove();
}
mem::drop(rem);
assert_eq!(vec, [5, 6, 7, 8, 9]);
}
#[test]
fn test() {
let mut vec: Vec<_> = (0..3).map(f).collect();
{
let mut rem = vec.removing();
rem.next().unwrap();
assert_eq!(rem.next().unwrap().remove(), 1);
rem.next().unwrap();
}
assert_eq!(vec, [0, 2]);
}
#[test]
fn zst() {
let mut vec: Vec<_> = (0..3).map(zf).collect();
{
let mut rem = vec.removing();
rem.next().unwrap();
rem.next().unwrap().remove();
rem.next().unwrap();
}
assert_eq!(vec.len(), 2);
}
}