external_buffered_stream/
lib.rs1mod buffer;
2mod error;
3mod runtime;
4mod serde;
5
6pub use buffer::*;
7pub use error::*;
8pub use serde::*;
9
10use std::{
11 marker::PhantomData,
12 pin::Pin,
13 sync::{
14 atomic::{AtomicBool, Ordering},
15 Arc,
16 },
17 task::{Context, Poll},
18};
19
20use futures::{channel::mpsc, Future, SinkExt, Stream, StreamExt};
21
22pub struct ExternalBufferedStream<T, B, S>
23where
24 T: Send,
25 B: ExternalBuffer<T>,
26 S: Stream<Item = T>,
27{
28 buffer: Arc<B>,
29 _source: PhantomData<S>,
30 notify: mpsc::UnboundedReceiver<()>,
31 stop_flag: Arc<AtomicBool>,
32
33 pending: Option<Pin<Box<dyn Future<Output = Result<Option<T>, Error>> + Send>>>,
35}
36
37impl<T, B, S> ExternalBufferedStream<T, B, S>
38where
39 T: Send,
40 B: ExternalBuffer<T> + 'static,
41 S: Stream<Item = T> + Send + 'static,
42{
43 pub fn new(source: S, buffer: B) -> Self {
44 let source = Box::pin(source);
45
46 let buffer = Arc::new(buffer);
47 let buffer_clone = buffer.clone();
48
49 let (notify_tx, notify_rx) = mpsc::unbounded::<()>();
50
51 let stop_flag = Arc::new(AtomicBool::new(false));
52 let stop_flag_clone = stop_flag.clone();
53
54 let handle_source = async move {
55 let mut source = source;
56 let mut notify_tx = notify_tx;
57 while let Some(item) = source.next().await {
58 match buffer_clone.push(item).await {
59 Ok(()) => match notify_tx.send(()).await {
60 Ok(_) => {}
61 Err(e) => {
62 log::error!("Failed to notify: {:?}", e);
63 break;
64 }
65 },
66 Err(e) => {
67 log::error!("Failed to push item to buffer: {:?}", e);
68 break;
69 }
70 }
71 }
72 log::info!("Source of external buffer stream is ended.");
73 stop_flag_clone.store(true, Ordering::SeqCst);
74 _ = notify_tx.send(())
75 };
76 runtime::spawn(handle_source);
77
78 ExternalBufferedStream {
79 buffer,
80 _source: PhantomData,
81 notify: notify_rx,
82 stop_flag,
83 pending: None,
84 }
85 }
86}
87
88impl<T, B, S> Stream for ExternalBufferedStream<T, B, S>
89where
90 T: Send,
91 B: ExternalBuffer<T> + 'static,
92 S: Stream<Item = T> + Send + 'static,
93{
94 type Item = T;
95
96 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
97 let this = unsafe { self.get_unchecked_mut() };
99
100 loop {
101 if this.stop_flag.load(Ordering::SeqCst) {
102 return Poll::Ready(None);
103 }
104
105 if let Some(pending) = this.pending.as_mut() {
106 match pending.as_mut().poll(cx) {
107 Poll::Ready(result) => {
108 this.pending = None;
109
110 match result {
111 Ok(Some(item)) => {
112 return Poll::Ready(Some(item));
113 }
114 Ok(None) => {
115 }
117 Err(err) => {
118 log::error!("external buffer shift return error: {}", err);
119 return Poll::Ready(None);
120 }
121 }
122 }
123 Poll::Pending => {
124 return Poll::Pending;
125 }
126 }
127 }
128
129 match (&mut this.notify).poll_next_unpin(cx) {
130 Poll::Ready(Some(_)) => {
131 let buffer = this.buffer.clone();
132 this.pending = Some(Box::pin(async move { buffer.shift().await }));
133 continue;
134 }
135 Poll::Ready(None) => return Poll::Ready(None),
136 Poll::Pending => return Poll::Pending,
137 }
138 }
139 }
140}
141
142#[cfg(feature = "default")]
143pub fn create_external_buffered_stream<T, S, P>(
144 stream: S,
145 path: P,
146) -> Result<ExternalBufferedStream<T, ExternalBufferSled, S>, Error>
147where
148 T: ExternalBufferSerde + Send + 'static,
149 S: Stream<Item = T> + Send + Sync + 'static,
150 P: AsRef<std::path::Path>,
151{
152 Ok(ExternalBufferedStream::new(
153 stream,
154 ExternalBufferSled::new(path)?,
155 ))
156}
157
158#[cfg(feature = "queue")]
159pub fn create_queued_stream<T, S>(
160 stream: S,
161) -> Result<ExternalBufferedStream<T, ExternalBufferQueue<T>, S>, Error>
162where
163 T: Ord + Send + 'static,
164 S: Stream<Item = T> + Send + Sync + 'static,
165{
166 Ok(ExternalBufferedStream::new(
167 stream,
168 ExternalBufferQueue::new(),
169 ))
170}