use futures_core::Stream;
use std::borrow::Borrow;
use std::collections::HashMap;
use std::future::poll_fn;
use std::hash::Hash;
use std::pin::Pin;
use std::task::{Context, Poll, ready};
#[derive(Debug, Clone)]
pub struct StreamMap<K, V> {
entries: Vec<(K, V)>,
index: HashMap<K, usize>,
}
impl<K, V> StreamMap<K, V> {
pub fn new() -> Self {
Self {
entries: Vec::new(),
index: HashMap::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
entries: Vec::with_capacity(capacity),
index: HashMap::with_capacity(capacity),
}
}
pub fn iter(&self) -> impl Iterator<Item = &(K, V)> {
self.entries.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
self.entries.iter_mut().map(|(key, stream)| (&*key, stream))
}
pub fn keys(&self) -> impl Iterator<Item = &K> {
self.entries.iter().map(|(k, _)| k)
}
pub fn values(&self) -> impl Iterator<Item = &V> {
self.entries.iter().map(|(_, v)| v)
}
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
self.entries.iter_mut().map(|(_, v)| v)
}
pub fn capacity(&self) -> usize {
self.entries.capacity()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn clear(&mut self) {
self.entries.clear();
self.index.clear();
}
pub fn insert(&mut self, k: K, stream: V) -> Option<V>
where
K: Hash + Eq + Clone,
{
if let Some(&pos) = self.index.get(&k) {
let slot = &mut self.entries[pos].1;
return Some(std::mem::replace(slot, stream));
}
let pos = self.entries.len();
self.index.insert(k.clone(), pos);
self.entries.push((k, stream));
None
}
pub fn remove<Q>(&mut self, k: &Q) -> Option<V>
where
K: Borrow<Q> + Hash + Eq + Clone,
Q: Hash + Eq + ?Sized,
{
let idx = *self.index.get(k)?;
self.index.remove(k);
Some(self.swap_remove_idx(idx).1)
}
pub fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + ?Sized,
{
self.index.contains_key(k)
}
pub fn get<Q>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + ?Sized,
{
let &idx = self.index.get(k)?;
self.entries.get(idx).map(|(_, v)| v)
}
pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + ?Sized,
{
let &idx = self.index.get(k)?;
self.entries.get_mut(idx).map(|(_, v)| v)
}
}
impl<K, V> StreamMap<K, V>
where
K: Clone,
{
fn swap_remove_idx(&mut self, idx: usize) -> (K, V)
where
K: Hash + Eq,
{
let out = self.entries.swap_remove(idx);
if idx < self.entries.len() {
let moved = self.entries[idx].0.clone();
self.index.insert(moved, idx);
}
out
}
}
impl<K, V> StreamMap<K, V>
where
K: Unpin,
V: Stream + Unpin,
{
fn poll_next_entry(&mut self, cx: &mut Context<'_>) -> Poll<Option<(usize, V::Item)>>
where
K: Hash + Eq + Clone,
{
if self.entries.is_empty() {
return Poll::Ready(None);
}
let start = crate::rand::thread_rng_n(self.entries.len() as u32) as usize;
let mut idx = start;
for _ in 0..self.entries.len() {
let (_, stream) = &mut self.entries[idx];
match Pin::new(stream).poll_next(cx) {
Poll::Ready(Some(val)) => return Poll::Ready(Some((idx, val))),
Poll::Ready(None) => {
let key = self.entries[idx].0.clone();
self.index.remove(&key);
self.swap_remove_idx(idx);
if self.entries.is_empty() {
return Poll::Ready(None);
}
if idx == self.entries.len() {
idx = 0;
} else if idx < start && start <= self.entries.len() {
idx = idx.wrapping_add(1) % self.entries.len();
}
}
Poll::Pending => {
idx = idx.wrapping_add(1) % self.entries.len();
}
}
}
if self.entries.is_empty() {
Poll::Ready(None)
} else {
Poll::Pending
}
}
}
impl<K, V> Default for StreamMap<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<K, V> StreamMap<K, V>
where
K: Clone + Unpin,
V: Stream + Unpin,
{
pub async fn next_many(&mut self, buffer: &mut Vec<(K, V::Item)>, limit: usize) -> usize
where
K: Hash + Eq,
{
poll_fn(|cx| self.poll_next_many(cx, buffer, limit)).await
}
pub fn poll_next_many(
&mut self,
cx: &mut Context<'_>,
buffer: &mut Vec<(K, V::Item)>,
limit: usize,
) -> Poll<usize>
where
K: Hash + Eq,
{
if limit == 0 || self.entries.is_empty() {
return Poll::Ready(0);
}
let mut added = 0;
let start = crate::rand::thread_rng_n(self.entries.len() as u32) as usize;
let mut idx = start;
while added < limit {
let mut made_progress = false;
for _ in 0..self.entries.len() {
if self.entries.is_empty() {
break;
}
let (_, stream) = &mut self.entries[idx];
match Pin::new(stream).poll_next(cx) {
Poll::Ready(Some(val)) => {
added += 1;
buffer.push((self.entries[idx].0.clone(), val));
made_progress = true;
idx = idx.wrapping_add(1) % self.entries.len();
if added == limit {
break;
}
}
Poll::Ready(None) => {
let key = self.entries[idx].0.clone();
self.index.remove(&key);
self.swap_remove_idx(idx);
if self.entries.is_empty() {
break;
}
if idx == self.entries.len() {
idx = 0;
} else if idx < start && start <= self.entries.len() {
idx = idx.wrapping_add(1) % self.entries.len();
}
}
Poll::Pending => {
idx = idx.wrapping_add(1) % self.entries.len();
}
}
}
if !made_progress {
break;
}
}
if added > 0 {
Poll::Ready(added)
} else if self.entries.is_empty() {
Poll::Ready(0)
} else {
Poll::Pending
}
}
}
impl<K, V> Stream for StreamMap<K, V>
where
K: Clone + Unpin,
V: Stream + Unpin,
K: Hash + Eq,
{
type Item = (K, V::Item);
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
if let Some((idx, val)) = ready!(self.poll_next_entry(cx)) {
let key = self.entries[idx].0.clone();
Poll::Ready(Some((key, val)))
} else {
Poll::Ready(None)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let mut lo: usize = 0;
let mut hi: Option<usize> = Some(0);
for (_, stream) in &self.entries {
let (a, b) = stream.size_hint();
lo = lo.saturating_add(a);
match (hi, b) {
(Some(x), Some(y)) => hi = x.checked_add(y),
(Some(_), None) => hi = None,
_ => {}
}
}
(lo, hi)
}
}
impl<K, V> FromIterator<(K, V)> for StreamMap<K, V>
where
K: Hash + Eq + Clone,
{
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let iter = iter.into_iter();
let (lo, _) = iter.size_hint();
let mut map = Self::with_capacity(lo);
for (k, v) in iter {
map.insert(k, v);
}
map
}
}
impl<K, V> Extend<(K, V)> for StreamMap<K, V>
where
K: Hash + Eq + Clone,
{
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (K, V)>,
{
for (k, v) in iter {
self.insert(k, v);
}
}
}