use std::pin::Pin; use std::sync::Arc; use futures_util::{Stream, StreamExt, stream}; use tokio::sync::{Mutex, Semaphore}; use crate::resource::Pull; type Producer = Pin> + Send>>; struct State { producer: Mutex>>, closed: Semaphore, } pub struct AsyncStream(Arc>); impl Clone for AsyncStream { fn clone(&self) -> Self { Self(Arc::clone(&self.0)) } } impl std::fmt::Debug for AsyncStream { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("AsyncStream()") } } impl AsyncStream { pub fn new(producer: impl Stream> + Send + 'static) -> Self { Self(Arc::new(State { producer: Mutex::new(Some(Box::pin(producer))), closed: Semaphore::new(0), })) } async fn pull_next(&self) -> Pull { let mut producer = self.0.producer.lock().await; let result = match producer.as_mut() { Some(producer) => tokio::select! { biased; _ = self.0.closed.acquire() => Pull::End, value = producer.next() => value.unwrap_or(Pull::End), }, None => Pull::End, }; if matches!(&result, Pull::Last(_) | Pull::End) { producer.take(); } result } pub async fn pull(&self) -> Option { match self.pull_next().await { Pull::Item(value) | Pull::Last(value) => Some(value), Pull::End => None, } } pub fn close(&self) { self.0.closed.close(); // 挂起的 pull 收到关闭信号后,会在其持有的锁内释放生产者。 if let Ok(mut producer) = self.0.producer.try_lock() { producer.take(); } } pub fn close_on_drop(&self) -> CloseOnDrop { CloseOnDrop(self.clone()) } } impl AsyncStream { pub fn from_values(values: impl IntoIterator) -> Self { Self::new(stream::iter(values.into_iter().map(Pull::Item))) } pub fn map( self, transform: impl FnMut(T) -> U + Send + 'static, ) -> AsyncStream { let owner = self.close_on_drop(); AsyncStream::new(stream::unfold( (owner, transform), |(owner, mut transform)| async move { let result = match owner.0.pull_next().await { Pull::Item(value) => Pull::Item(transform(value)), Pull::Last(value) => Pull::Last(transform(value)), Pull::End => return None, }; Some((result, (owner, transform))) }, )) } } pub struct CloseOnDrop(AsyncStream); impl Drop for CloseOnDrop { fn drop(&mut self) { self.0.close(); } }