Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement the SortBy stream adapter #43

Merged
merged 9 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eyeball-im-util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ keywords.workspace = true
all-features = true

[dependencies]
arrayvec = "0.7.4"
eyeball-im = { version = "0.4.2", path = "../eyeball-im" }
futures-core.workspace = true
imbl = "2.0.0"
pin-project-lite = "0.2.9"
smallvec = { version = "1.11.2", features = ["const_generics", "const_new"] }

[dev-dependencies]
eyeball = { version = "0.8.6", path = "../eyeball" }
Expand Down
4 changes: 3 additions & 1 deletion eyeball-im-util/src/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod filter;
mod limit;
mod ops;
mod sort;
mod traits;

use eyeball_im::VectorDiff;
Expand All @@ -12,6 +13,7 @@ use self::ops::{VectorDiffContainerFamilyMember, VectorDiffContainerOps};
pub use self::{
filter::{Filter, FilterMap},
limit::{EmptyLimitStream, Limit},
sort::SortBy,
traits::{
BatchedVectorSubscriber, VectorDiffContainer, VectorObserver, VectorObserverExt,
VectorSubscriberExt,
Expand Down Expand Up @@ -40,5 +42,5 @@ type VectorDiffContainerDiff<S> = VectorDiff<VectorDiffContainerStreamElement<S>

/// Type alias for extracting the buffer type from a stream of
/// [`VectorDiffContainer`]s.
type VectorDiffContainerStreamLimitBuf<S> =
type VectorDiffContainerStreamBuffer<S> =
<<S as Stream>::Item as VectorDiffContainerOps<VectorDiffContainerStreamElement<S>>>::Buffer;
15 changes: 8 additions & 7 deletions eyeball-im-util/src/vector/limit.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use smallvec::SmallVec;
use std::{
cmp::{min, Ordering},
mem,
Expand All @@ -6,10 +7,9 @@ use std::{
};

use super::{
VectorDiffContainer, VectorDiffContainerOps, VectorDiffContainerStreamElement,
VectorDiffContainerStreamLimitBuf, VectorObserver,
VectorDiffContainer, VectorDiffContainerOps, VectorDiffContainerStreamBuffer,
VectorDiffContainerStreamElement, VectorObserver,
};
use arrayvec::ArrayVec;
use eyeball_im::VectorDiff;
use futures_core::Stream;
use imbl::Vector;
Expand Down Expand Up @@ -63,7 +63,7 @@ pin_project! {
// with a limit of 2 on top: if an item is popped at the front then 10
// is removed, but 12 has to be pushed back as it "enters" the "view".
// That second `PushBack` diff is buffered here.
ready_values: VectorDiffContainerStreamLimitBuf<S>,
ready_values: VectorDiffContainerStreamBuffer<S>,
}
}

Expand Down Expand Up @@ -207,6 +207,7 @@ where
update_buffered_vector(&diff, self.buffered_vector);
handle_diff(diff, limit, prev_len, self.buffered_vector)
});

if let Some(diff) = ready {
return Poll::Ready(Some(diff));
}
Expand Down Expand Up @@ -318,15 +319,15 @@ fn handle_diff<T: Clone>(
limit: usize,
prev_len: usize,
buffered_vector: &Vector<T>,
) -> ArrayVec<VectorDiff<T>, 2> {
) -> SmallVec<[VectorDiff<T>; 2]> {
// If the limit is zero, we have nothing to do.
if limit == 0 {
return ArrayVec::new();
return SmallVec::new();
}

let is_full = prev_len >= limit;
let mut res = SmallVec::new();

let mut res = ArrayVec::new();
match diff {
VectorDiff::Append { mut values } => {
if is_full {
Expand Down
33 changes: 20 additions & 13 deletions eyeball-im-util/src/vector/ops.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use arrayvec::ArrayVec;
use eyeball_im::VectorDiff;
use smallvec::SmallVec;

pub trait VectorDiffContainerOps<T>: Sized {
type Family: VectorDiffContainerFamily;
Expand All @@ -15,7 +15,7 @@ pub trait VectorDiffContainerOps<T>: Sized {
fn push_into_buffer(
self,
buffer: &mut Self::Buffer,
make_diffs: impl FnMut(VectorDiff<T>) -> ArrayVec<VectorDiff<T>, 2>,
make_diffs: impl FnMut(VectorDiff<T>) -> SmallVec<[VectorDiff<T>; 2]>,
) -> Option<Self>;

fn pop_from_buffer(buffer: &mut Self::Buffer) -> Option<Self>;
Expand All @@ -26,7 +26,7 @@ pub type VectorDiffContainerFamilyMember<F, U> = <F as VectorDiffContainerFamily

impl<T> VectorDiffContainerOps<T> for VectorDiff<T> {
type Family = VectorDiffFamily;
type Buffer = Option<VectorDiff<T>>;
type Buffer = SmallVec<[VectorDiff<T>; 2]>;

fn from_item(vector_diff: VectorDiff<T>) -> Self {
vector_diff
Expand All @@ -42,23 +42,28 @@ impl<T> VectorDiffContainerOps<T> for VectorDiff<T> {
fn push_into_buffer(
self,
buffer: &mut Self::Buffer,
mut make_diffs: impl FnMut(VectorDiff<T>) -> ArrayVec<VectorDiff<T>, 2>,
mut make_diffs: impl FnMut(VectorDiff<T>) -> SmallVec<[VectorDiff<T>; 2]>,
) -> Option<Self> {
assert!(buffer.is_none(), "buffer must be None when calling push_into_buffer");
assert!(buffer.is_empty(), "buffer must be empty when calling `push_into_buffer`");

let mut diffs = make_diffs(self);

let last = diffs.pop();
if let Some(first) = diffs.pop() {
*buffer = last;
Some(first)
} else {
last
match diffs.len() {
0 => None,
1 => diffs.pop(),
_ => {
// We want the first element. We can't “pop front” on a `SmallVec`.
// The idea is to reverse the `diffs` and to pop from it.
diffs.reverse();
*buffer = diffs;

buffer.pop()
}
}
}

fn pop_from_buffer(buffer: &mut Self::Buffer) -> Option<Self> {
buffer.take()
buffer.pop()
}
}

Expand All @@ -75,6 +80,7 @@ impl<T> VectorDiffContainerOps<T> for Vec<VectorDiff<T>> {
f: impl FnMut(VectorDiff<T>) -> Option<VectorDiff<U>>,
) -> Option<VectorDiffContainerFamilyMember<Self::Family, U>> {
let res: Vec<_> = self.into_iter().filter_map(f).collect();

if res.is_empty() {
None
} else {
Expand All @@ -85,9 +91,10 @@ impl<T> VectorDiffContainerOps<T> for Vec<VectorDiff<T>> {
fn push_into_buffer(
self,
_buffer: &mut (),
make_diffs: impl FnMut(VectorDiff<T>) -> ArrayVec<VectorDiff<T>, 2>,
make_diffs: impl FnMut(VectorDiff<T>) -> SmallVec<[VectorDiff<T>; 2]>,
) -> Option<Self> {
let res: Vec<_> = self.into_iter().flat_map(make_diffs).collect();

if res.is_empty() {
None
} else {
Expand Down
Loading