use crate::DynamicMerge;
use futures_core::Stream;
use futures_util::stream::SelectAll;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll};
pub struct DynamicMergeHandle<'a, T> {
shared: Arc<Mutex<DynamicMerge<'a, T>>>,
}
impl<'a, T> DynamicMergeHandle<'a, T> {
pub fn push<S>(&mut self, stream: S)
where
S: Stream<Item = T> + Send + 'a,
{
self.shared.lock().unwrap().push(Box::pin(stream));
}
pub fn len(&self) -> usize {
self.shared.lock().unwrap().len()
}
pub fn is_empty(&self) -> bool {
self.shared.lock().unwrap().is_empty()
}
pub fn clear(&mut self) {
self.shared.lock().unwrap().clear();
}
}
impl<'a, T> Clone for DynamicMergeHandle<'a, T> {
fn clone(&self) -> Self {
Self {
shared: Arc::clone(&self.shared),
}
}
}
pub struct DynamicMergeStream<'a, T> {
shared: Arc<Mutex<DynamicMerge<'a, T>>>,
}
impl<'a, T> Stream for DynamicMergeStream<'a, T> {
type Item = T;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut shared = self.shared.lock().unwrap();
Pin::new(&mut *shared).poll_next(cx)
}
}
pub fn dynamic_merge_with_handle<'a, T>() -> (DynamicMergeStream<'a, T>, DynamicMergeHandle<'a, T>)
{
let shared = Arc::new(Mutex::new(SelectAll::new()));
let stream = DynamicMergeStream {
shared: Arc::clone(&shared),
};
let handle = DynamicMergeHandle { shared };
(stream, handle)
}
#[cfg(test)]
mod tests {
use super::*;
use futures_util::stream::{self, StreamExt};
#[tokio::test]
async fn test_basic_handle_usage() {
let (mut stream, mut handle) = dynamic_merge_with_handle::<i32>();
handle.push(stream::iter(vec![1, 2, 3]));
handle.push(stream::iter(vec![4, 5, 6]));
let mut items = Vec::new();
while let Some(item) = stream.next().await {
items.push(item);
}
items.sort();
assert_eq!(items, vec![1, 2, 3, 4, 5, 6]);
}
#[tokio::test]
async fn test_separate_mutable_access() {
let (mut stream, mut handle) = dynamic_merge_with_handle::<i32>();
handle.push(stream::iter(vec![1, 2, 3]));
handle.push(stream::iter(vec![4, 5, 6]));
let mut items = Vec::new();
while let Some(item) = stream.next().await {
items.push(item);
}
items.sort();
assert_eq!(items, vec![1, 2, 3, 4, 5, 6]);
}
#[tokio::test]
async fn test_handle_clone() {
let (mut stream, mut handle1) = dynamic_merge_with_handle::<i32>();
let mut handle2 = handle1.clone();
handle1.push(stream::iter(vec![1, 2, 3]));
handle2.push(stream::iter(vec![4, 5, 6]));
let mut items = Vec::new();
while let Some(item) = stream.next().await {
items.push(item);
}
items.sort();
assert_eq!(items, vec![1, 2, 3, 4, 5, 6]);
}
#[test]
fn test_handle_len_and_empty() {
let (_stream, mut handle) = dynamic_merge_with_handle::<i32>();
assert!(handle.is_empty());
assert_eq!(handle.len(), 0);
handle.push(stream::iter(vec![1, 2, 3]));
assert!(!handle.is_empty());
assert_eq!(handle.len(), 1);
handle.push(stream::iter(vec![4, 5, 6]));
assert_eq!(handle.len(), 2);
}
#[test]
fn test_handle_clear() {
let (_stream, mut handle) = dynamic_merge_with_handle::<i32>();
handle.push(stream::iter(vec![1, 2, 3]));
handle.push(stream::iter(vec![4, 5, 6]));
assert_eq!(handle.len(), 2);
handle.clear();
assert_eq!(handle.len(), 0);
assert!(handle.is_empty());
}
#[tokio::test]
async fn test_dynamic_push_while_polling() {
let (mut stream, mut handle) = dynamic_merge_with_handle::<i32>();
handle.push(stream::iter(vec![1, 2]));
let item1 = stream.next().await;
assert!(item1.is_some());
handle.push(stream::iter(vec![3, 4]));
let item2 = stream.next().await;
assert!(item2.is_some());
let item3 = stream.next().await;
assert!(item3.is_some());
let item4 = stream.next().await;
assert!(item4.is_some());
}
}