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