Skip to content

Commit a0193fa

Browse files
committed
Added FromStream + Extend for HashSet
1 parent ee993e2 commit a0193fa

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

src/collections/hash_set/extend.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use std::pin::Pin;
2+
use std::hash::{Hash, BuildHasher};
3+
use std::collections::HashSet;
4+
5+
use crate::prelude::*;
6+
use crate::stream::{Extend, IntoStream};
7+
8+
impl<T, H> Extend<T> for HashSet<T, H>
9+
where T: Eq + Hash,
10+
H: BuildHasher + Default {
11+
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
12+
&'a mut self,
13+
stream: S,
14+
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
15+
// The Extend impl for HashSet in the standard library delegates to the internal HashMap.
16+
// Thus, this impl is just a copy of the async Extend impl for HashMap in this crate.
17+
18+
let stream = stream.into_stream();
19+
20+
// The following is adapted from the hashbrown source code:
21+
// https://github.com/rust-lang/hashbrown/blob/d1ad4fc3aae2ade446738eea512e50b9e863dd0c/src/map.rs#L2470-L2491
22+
//
23+
// Keys may be already present or show multiple times in the stream. Reserve the entire
24+
// hint lower bound if the map is empty. Otherwise reserve half the hint (rounded up), so
25+
// the map will only resize twice in the worst case.
26+
27+
//TODO: Add this back in when size_hint is added to Stream/StreamExt
28+
//let reserve = if self.is_empty() {
29+
// stream.size_hint().0
30+
//} else {
31+
// (stream.size_hint().0 + 1) / 2
32+
//};
33+
//self.reserve(reserve);
34+
35+
Box::pin(stream.for_each(move |item| {
36+
self.insert(item);
37+
}))
38+
}
39+
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use std::pin::Pin;
2+
use std::hash::{Hash, BuildHasher};
3+
use std::collections::HashSet;
4+
5+
use crate::stream::{Extend, FromStream, IntoStream};
6+
7+
impl<T, H> FromStream<T> for HashSet<T, H>
8+
where T: Eq + Hash,
9+
H: BuildHasher + Default {
10+
#[inline]
11+
fn from_stream<'a, S: IntoStream<Item = T>>(
12+
stream: S,
13+
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
14+
where
15+
<S as IntoStream>::IntoStream: 'a,
16+
{
17+
let stream = stream.into_stream();
18+
19+
Box::pin(async move {
20+
pin_utils::pin_mut!(stream);
21+
22+
let mut out = HashSet::with_hasher(Default::default());
23+
out.stream_extend(stream).await;
24+
out
25+
})
26+
}
27+
}

src/collections/hash_set/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//! The Rust hash set, implemented as a `HashMap` where the value is `()`.
2+
3+
mod extend;
4+
mod from_stream;
5+
6+
#[doc(inline)]
7+
pub use std::collections::HashSet;

src/collections/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
66
pub mod vec_deque;
77
pub mod hash_map;
8+
pub mod hash_set;
89
pub mod btree_map;
910

1011
pub use vec_deque::VecDeque;
1112
pub use hash_map::HashMap;
13+
pub use hash_set::HashSet;
1214
pub use btree_map::BTreeMap;

0 commit comments

Comments
 (0)