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

FromStream impls for collections (and more!) #271

Merged
merged 13 commits into from
Oct 5, 2019
18 changes: 18 additions & 0 deletions src/collections/binary_heap/extend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::collections::BinaryHeap;
use std::pin::Pin;

use crate::prelude::*;
use crate::stream::{Extend, IntoStream};

impl<T: Ord> Extend<T> for BinaryHeap<T> {
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let (lower_bound, _) = stream.size_hint();
//self.reserve(lower_bound);
Box::pin(stream.for_each(move |item| self.push(item)))
}
}
24 changes: 24 additions & 0 deletions src/collections/binary_heap/from_stream.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use std::collections::BinaryHeap;
use std::pin::Pin;

use crate::stream::{Extend, FromStream, IntoStream};

impl<T: Ord> FromStream<T> for BinaryHeap<T> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = T>>(
stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
where
<S as IntoStream>::IntoStream: 'a,
{
let stream = stream.into_stream();

Box::pin(async move {
pin_utils::pin_mut!(stream);

let mut out = BinaryHeap::new();
out.stream_extend(stream).await;
out
})
}
}
7 changes: 7 additions & 0 deletions src/collections/binary_heap/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! The Rust priority queue implemented with a binary heap

mod extend;
mod from_stream;

#[doc(inline)]
pub use std::collections::BinaryHeap;
16 changes: 16 additions & 0 deletions src/collections/btree_map/extend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::collections::BTreeMap;
use std::pin::Pin;

use crate::prelude::*;
use crate::stream::{Extend, IntoStream};

impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
fn stream_extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
Box::pin(stream.into_stream().for_each(move |(k, v)| {
self.insert(k, v);
}))
}
}
24 changes: 24 additions & 0 deletions src/collections/btree_map/from_stream.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use std::collections::BTreeMap;
use std::pin::Pin;

use crate::stream::{Extend, FromStream, IntoStream};

impl<K: Ord, V> FromStream<(K, V)> for BTreeMap<K, V> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = (K, V)>>(
stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
where
<S as IntoStream>::IntoStream: 'a,
{
let stream = stream.into_stream();

Box::pin(async move {
pin_utils::pin_mut!(stream);

let mut out = BTreeMap::new();
out.stream_extend(stream).await;
out
})
}
}
7 changes: 7 additions & 0 deletions src/collections/btree_map/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! The Rust B-Tree Map

mod extend;
mod from_stream;

#[doc(inline)]
pub use std::collections::BTreeMap;
16 changes: 16 additions & 0 deletions src/collections/btree_set/extend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::collections::BTreeSet;
use std::pin::Pin;

use crate::prelude::*;
use crate::stream::{Extend, IntoStream};

impl<T: Ord> Extend<T> for BTreeSet<T> {
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
Box::pin(stream.into_stream().for_each(move |item| {
self.insert(item);
}))
}
}
24 changes: 24 additions & 0 deletions src/collections/btree_set/from_stream.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use std::collections::BTreeSet;
use std::pin::Pin;

use crate::stream::{Extend, FromStream, IntoStream};

impl<T: Ord> FromStream<T> for BTreeSet<T> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = T>>(
stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
where
<S as IntoStream>::IntoStream: 'a,
{
let stream = stream.into_stream();

Box::pin(async move {
pin_utils::pin_mut!(stream);

let mut out = BTreeSet::new();
out.stream_extend(stream).await;
out
})
}
}
7 changes: 7 additions & 0 deletions src/collections/btree_set/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! The Rust B-Tree Set

mod extend;
mod from_stream;

#[doc(inline)]
pub use std::collections::BTreeSet;
38 changes: 38 additions & 0 deletions src/collections/hash_map/extend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use std::collections::HashMap;
use std::hash::{BuildHasher, Hash};
use std::pin::Pin;

use crate::prelude::*;
use crate::stream::{Extend, IntoStream};

impl<K, V, H> Extend<(K, V)> for HashMap<K, V, H>
where
K: Eq + Hash,
H: BuildHasher + Default,
{
fn stream_extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();

// The following is adapted from the hashbrown source code:
// https://github.com/rust-lang/hashbrown/blob/d1ad4fc3aae2ade446738eea512e50b9e863dd0c/src/map.rs#L2470-L2491
//
// Keys may be already present or show multiple times in the stream. Reserve the entire
// hint lower bound if the map is empty. Otherwise reserve half the hint (rounded up), so
// the map will only resize twice in the worst case.

//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let reserve = if self.is_empty() {
// stream.size_hint().0
//} else {
// (stream.size_hint().0 + 1) / 2
//};
//self.reserve(reserve);

Box::pin(stream.for_each(move |(k, v)| {
self.insert(k, v);
}))
}
}
29 changes: 29 additions & 0 deletions src/collections/hash_map/from_stream.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::collections::HashMap;
use std::hash::{BuildHasher, Hash};
use std::pin::Pin;

use crate::stream::{Extend, FromStream, IntoStream};

impl<K, V, H> FromStream<(K, V)> for HashMap<K, V, H>
where
K: Eq + Hash,
H: BuildHasher + Default,
{
#[inline]
fn from_stream<'a, S: IntoStream<Item = (K, V)>>(
stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
where
<S as IntoStream>::IntoStream: 'a,
{
let stream = stream.into_stream();

Box::pin(async move {
pin_utils::pin_mut!(stream);

let mut out = HashMap::with_hasher(Default::default());
out.stream_extend(stream).await;
out
})
}
}
7 changes: 7 additions & 0 deletions src/collections/hash_map/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! The Rust hash map, implemented with quadratic probing and SIMD lookup.

mod extend;
mod from_stream;

#[doc(inline)]
pub use std::collections::HashMap;
41 changes: 41 additions & 0 deletions src/collections/hash_set/extend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use std::collections::HashSet;
use std::hash::{BuildHasher, Hash};
use std::pin::Pin;

use crate::prelude::*;
use crate::stream::{Extend, IntoStream};

impl<T, H> Extend<T> for HashSet<T, H>
where
T: Eq + Hash,
H: BuildHasher + Default,
{
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
// The Extend impl for HashSet in the standard library delegates to the internal HashMap.
// Thus, this impl is just a copy of the async Extend impl for HashMap in this crate.

let stream = stream.into_stream();

// The following is adapted from the hashbrown source code:
// https://github.com/rust-lang/hashbrown/blob/d1ad4fc3aae2ade446738eea512e50b9e863dd0c/src/map.rs#L2470-L2491
//
// Keys may be already present or show multiple times in the stream. Reserve the entire
// hint lower bound if the map is empty. Otherwise reserve half the hint (rounded up), so
// the map will only resize twice in the worst case.

//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let reserve = if self.is_empty() {
// stream.size_hint().0
//} else {
// (stream.size_hint().0 + 1) / 2
//};
//self.reserve(reserve);

Box::pin(stream.for_each(move |item| {
self.insert(item);
}))
}
}
29 changes: 29 additions & 0 deletions src/collections/hash_set/from_stream.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::collections::HashSet;
use std::hash::{BuildHasher, Hash};
use std::pin::Pin;

use crate::stream::{Extend, FromStream, IntoStream};

impl<T, H> FromStream<T> for HashSet<T, H>
where
T: Eq + Hash,
H: BuildHasher + Default,
{
#[inline]
fn from_stream<'a, S: IntoStream<Item = T>>(
stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
where
<S as IntoStream>::IntoStream: 'a,
{
let stream = stream.into_stream();

Box::pin(async move {
pin_utils::pin_mut!(stream);

let mut out = HashSet::with_hasher(Default::default());
out.stream_extend(stream).await;
out
})
}
}
7 changes: 7 additions & 0 deletions src/collections/hash_set/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! The Rust hash set, implemented as a `HashMap` where the value is `()`.

mod extend;
mod from_stream;

#[doc(inline)]
pub use std::collections::HashSet;
18 changes: 18 additions & 0 deletions src/collections/linked_list/extend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::collections::LinkedList;
use std::pin::Pin;

use crate::prelude::*;
use crate::stream::{Extend, IntoStream};

impl<T> Extend<T> for LinkedList<T> {
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self,
stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
let stream = stream.into_stream();
//TODO: Add this back in when size_hint is added to Stream/StreamExt
//let (lower_bound, _) = stream.size_hint();
//self.reserve(lower_bound);
Box::pin(stream.for_each(move |item| self.push_back(item)))
}
}
24 changes: 24 additions & 0 deletions src/collections/linked_list/from_stream.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use std::collections::LinkedList;
use std::pin::Pin;

use crate::stream::{Extend, FromStream, IntoStream};

impl<T> FromStream<T> for LinkedList<T> {
#[inline]
fn from_stream<'a, S: IntoStream<Item = T>>(
stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>>
where
<S as IntoStream>::IntoStream: 'a,
{
let stream = stream.into_stream();

Box::pin(async move {
pin_utils::pin_mut!(stream);

let mut out = LinkedList::new();
out.stream_extend(stream).await;
out
})
}
}
7 changes: 7 additions & 0 deletions src/collections/linked_list/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! The Rust doubly-linked list with owned nodes

mod extend;
mod from_stream;

#[doc(inline)]
pub use std::collections::LinkedList;
20 changes: 20 additions & 0 deletions src/collections/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! The Rust standard collections
//!
//! This library provides efficient implementations of the most common general purpose programming
//! data structures.

pub mod binary_heap;
pub mod btree_map;
pub mod btree_set;
pub mod hash_map;
pub mod hash_set;
pub mod linked_list;
pub mod vec_deque;

pub use binary_heap::BinaryHeap;
pub use btree_map::BTreeMap;
pub use btree_set::BTreeSet;
pub use hash_map::HashMap;
pub use hash_set::HashSet;
pub use linked_list::LinkedList;
pub use vec_deque::VecDeque;
Loading