Skip to content

Commit

Permalink
Implement Saturate more explicitly for collections.
Browse files Browse the repository at this point in the history
This change replaces the blanket implementation of `Saturate` bound on
`Extend` and `Vacancy` with more explicit implementations for
collections. This avoids an incorrect implementation for relational
collection types with some notion of capacity (that implement `Extend`
and `Vacancy`). In particular, `BinaryHeap` may implement these traits
and but requires a different `Saturate` implementation.
  • Loading branch information
olson-sean-k committed Jul 29, 2024
1 parent ccd7432 commit bfcbc0d
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 61 deletions.
56 changes: 55 additions & 1 deletion src/array_vec1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::segment::{self, Ranged, Segment, Segmentation, Segmented};
#[cfg(feature = "serde")]
use crate::serde::{EmptyError, Serde};
use crate::slice1::Slice1;
use crate::{NonEmpty, OptionExt as _, Saturated, Vacancy};
use crate::{NonEmpty, OptionExt as _, Saturate, Saturated, Vacancy};

impl<T, const N: usize> Ranged for ArrayVec<T, N> {
type Range = PositionalRange;
Expand All @@ -33,6 +33,30 @@ impl<T, const N: usize> Ranged for ArrayVec<T, N> {
}
}

impl<T, I, const N: usize> Saturate<I> for ArrayVec<T, N>
where
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<T, I, const N: usize> Saturated<I> for ArrayVec<T, N>
where
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturated(items: I) -> (Self, Self::Remainder) {
let mut remainder = items.into_iter();
let items: ArrayVec<_, N> = remainder.by_ref().take(N).collect();
(items, remainder)
}
}

impl<T, const N: usize> Segmentation for ArrayVec<T, N> {
fn tail(&mut self) -> ArrayVecSegment<'_, T, N> {
self.segment(Ranged::tail(self))
Expand All @@ -57,6 +81,12 @@ where
}
}

impl<T, const N: usize> Vacancy for ArrayVec<T, N> {
fn vacancy(&self) -> usize {
self.capacity() - self.len()
}
}

pub type ArrayVec1<T, const N: usize> = NonEmpty<ArrayVec<T, N>>;

impl<T, const N: usize> ArrayVec1<T, N>
Expand Down Expand Up @@ -422,6 +452,18 @@ impl<T, const N: usize> IntoIterator1 for ArrayVec1<T, N> {
}
}

impl<T, I, const N: usize> Saturate<I> for ArrayVec1<T, N>
where
[T; N]: Array1,
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<T, I, const N: usize> Saturated<I> for ArrayVec1<T, N>
where
[T; N]: Array1,
Expand Down Expand Up @@ -705,6 +747,18 @@ where
}
}

impl<'a, K, T, I, const N: usize> Saturate<I> for Segment<'a, K, ArrayVec<T, N>>
where
K: Segmented<Target = ArrayVec<T, N>>,
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<'a, K, T, const N: usize> Ord for Segment<'a, K, ArrayVec<T, N>>
where
K: Segmented<Target = ArrayVec<T, N>>,
Expand Down
70 changes: 12 additions & 58 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,12 @@ pub mod prelude {
};
}

#[cfg(feature = "arrayvec")]
use arrayvec::ArrayVec;
use core::num::NonZeroUsize;
#[cfg(feature = "serde")]
use {
::serde::{Deserialize, Serialize},
::serde_derive::{Deserialize, Serialize},
};
#[cfg(feature = "alloc")]
use {alloc::collections::vec_deque::VecDeque, alloc::vec::Vec};

#[cfg(feature = "serde")]
use crate::serde::{EmptyError, Serde};
Expand Down Expand Up @@ -132,72 +128,18 @@ pub trait Vacancy {
fn vacancy(&self) -> usize;
}

#[cfg(feature = "arrayvec")]
#[cfg_attr(docsrs, doc(cfg(feature = "arrayvec")))]
impl<T, const N: usize> Vacancy for ArrayVec<T, N> {
fn vacancy(&self) -> usize {
self.capacity() - self.len()
}
}

#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T> Vacancy for Vec<T> {
fn vacancy(&self) -> usize {
self.capacity() - self.len()
}
}

#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T> Vacancy for VecDeque<T> {
fn vacancy(&self) -> usize {
self.capacity() - self.len()
}
}

pub trait Saturated<T>: Sized {
type Remainder;

fn saturated(items: T) -> (Self, Self::Remainder);
}

#[cfg(feature = "arrayvec")]
#[cfg_attr(docsrs, doc(cfg(feature = "arrayvec")))]
impl<T, I, const N: usize> Saturated<I> for ArrayVec<T, N>
where
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturated(items: I) -> (Self, Self::Remainder) {
let mut remainder = items.into_iter();
let items: ArrayVec<_, N> = remainder.by_ref().take(N).collect();
(items, remainder)
}
}

pub trait Saturate<T> {
type Remainder;

fn saturate(&mut self, items: T) -> Self::Remainder;
}

impl<T, I> Saturate<I> for T
where
T: Extend<I::Item> + Vacancy,
I: IntoIterator,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
let n = self.vacancy();
let mut items = items.into_iter();
self.extend(items.by_ref().take(n));
items
}
}

#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(
feature = "serde",
Expand Down Expand Up @@ -280,6 +222,18 @@ impl<T> Cardinality<T, T> {
}
}

#[cfg(any(feature = "alloc", feature = "arrayvec"))]
fn saturate_positional_vacancy<T, I>(destination: &mut T, source: I) -> I::IntoIter
where
T: Extend<I::Item> + Vacancy,
I: IntoIterator,
{
let n = destination.vacancy();
let mut source = source.into_iter();
destination.extend(source.by_ref().take(n));
source
}

macro_rules! with_literals {
($f:ident$(,)?) => {};
($f:ident, [$($N:literal $(,)?)+]$(,)?) => {
Expand Down
42 changes: 41 additions & 1 deletion src/vec1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::serde::{EmptyError, Serde};
use crate::slice1::Slice1;
#[cfg(target_has_atomic = "ptr")]
use crate::sync1::{ArcSlice1, ArcSlice1Ext as _};
use crate::{NonEmpty, NonZeroExt as _, OptionExt as _, Vacancy};
use crate::{NonEmpty, NonZeroExt as _, OptionExt as _, Saturate, Vacancy};

impl<T> Ranged for Vec<T> {
type Range = PositionalRange;
Expand All @@ -39,6 +39,17 @@ impl<T> Ranged for Vec<T> {
}
}

impl<T, I> Saturate<I> for Vec<T>
where
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<T> Segmentation for Vec<T> {
fn tail(&mut self) -> VecSegment<'_, T> {
self.segment(Ranged::tail(self))
Expand All @@ -63,6 +74,12 @@ where
}
}

impl<T> Vacancy for Vec<T> {
fn vacancy(&self) -> usize {
self.capacity() - self.len()
}
}

pub type CowSlice1<'a, T> = Cow<'a, Slice1<T>>;

pub trait CowSlice1Ext<'a, T>
Expand Down Expand Up @@ -439,6 +456,17 @@ impl<T> IntoIterator1 for Vec1<T> {
}
}

impl<T, I> Saturate<I> for Vec1<T>
where
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<T> Segmentation for Vec1<T> {
fn tail(&mut self) -> Vec1Segment<'_, T> {
self.segment(Ranged::tail(&self.items))
Expand Down Expand Up @@ -915,6 +943,18 @@ where
}
}

impl<'a, K, T, I> Saturate<I> for Segment<'a, K, Vec<T>>
where
K: Segmented<Target = Vec<T>>,
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<'a, K, T> Segmentation for Segment<'a, K, Vec<T>>
where
K: Segmented<Target = Vec<T>>,
Expand Down
48 changes: 47 additions & 1 deletion src/vec_deque1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::segment::{self, Ranged, Segment, Segmentation, Segmented};
#[cfg(feature = "serde")]
use crate::serde::{EmptyError, Serde};
use crate::slice1::Slice1;
use crate::{NonEmpty, NonZeroExt as _, OptionExt as _, Vacancy};
use crate::{NonEmpty, NonZeroExt as _, OptionExt as _, Saturate, Vacancy};

impl<T> Ranged for VecDeque<T> {
type Range = PositionalRange;
Expand All @@ -33,6 +33,17 @@ impl<T> Ranged for VecDeque<T> {
}
}

impl<T, I> Saturate<I> for VecDeque<T>
where
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<T> Segmentation for VecDeque<T> {
fn tail(&mut self) -> VecDequeSegment<'_, T> {
Segment::intersect(self, &Ranged::tail(self))
Expand All @@ -57,6 +68,12 @@ where
}
}

impl<T> Vacancy for VecDeque<T> {
fn vacancy(&self) -> usize {
self.capacity() - self.len()
}
}

pub type VecDeque1<T> = NonEmpty<VecDeque<T>>;

impl<T> VecDeque1<T> {
Expand Down Expand Up @@ -333,6 +350,17 @@ impl<T> IntoIterator1 for VecDeque1<T> {
}
}

impl<T, I> Saturate<I> for VecDeque1<T>
where
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<T> Segmentation for VecDeque1<T> {
fn tail(&mut self) -> VecDeque1Segment<'_, T> {
let range = Ranged::tail(&self.items);
Expand Down Expand Up @@ -381,6 +409,12 @@ impl<T> TryFrom<VecDeque<T>> for VecDeque1<T> {
}
}

impl<T> Vacancy for VecDeque1<T> {
fn vacancy(&self) -> usize {
self.items.vacancy()
}
}

pub type VecDequeSegment<'a, T> = Segment<'a, VecDeque<T>, VecDeque<T>>;

pub type VecDeque1Segment<'a, T> = Segment<'a, VecDeque1<T>, VecDeque<T>>;
Expand Down Expand Up @@ -585,6 +619,18 @@ where
}
}

impl<'a, K, T, I> Saturate<I> for Segment<'a, K, VecDeque<T>>
where
K: Segmented<Target = VecDeque<T>>,
I: IntoIterator<Item = T>,
{
type Remainder = I::IntoIter;

fn saturate(&mut self, items: I) -> Self::Remainder {
crate::saturate_positional_vacancy(self, items)
}
}

impl<'a, K, T> Segmentation for Segment<'a, K, VecDeque<T>>
where
K: Segmented<Target = VecDeque<T>>,
Expand Down

0 comments on commit bfcbc0d

Please sign in to comment.