use async_channel::{bounded, Receiver, SendError, Sender};
use futures_lite::{ready, AsyncRead, StreamExt};
use log::{trace, warn};
use std::{
io,
task::Poll,
thread::{self, JoinHandle},
time::Duration,
};
pub(crate) type DefaultStdIn = AsyncReader<io::Stdin>;
pub(crate) fn async_input() -> DefaultStdIn {
DefaultStdIn::default()
}
pub struct AsyncReader<R> {
stop_sender: Sender<()>,
buff_receiver: Receiver<Vec<u8>>,
join_handle: Option<JoinHandle<(R, io::Result<Vec<u8>>)>>,
buffer: Vec<u8>,
}
impl Default for AsyncReader<io::Stdin> {
fn default() -> Self {
Self::new(io::stdin())
}
}
impl<R> AsyncReader<R>
where
R: io::Read,
R: Send + 'static,
{
pub fn new(mut read: R) -> Self {
let (stop_sender, stop_receiver) = bounded(1);
let (buff_sender, buff_receiver) = bounded(1);
let mut buf = [0; 1024];
let join_handle = Some(thread::spawn(move || 'reading: loop {
match stop_receiver.try_recv() {
Ok(()) | Err(async_channel::TryRecvError::Closed) => break (read, Ok(vec![])),
Err(async_channel::TryRecvError::Empty) => {}
}
break match read.read(&mut buf) {
Ok(0) => (read, Ok(vec![])),
Err(e) => (read, Err(e)),
Ok(len) => {
let mut sendit = buf[0..len].to_vec();
loop {
if let Ok(()) = stop_receiver.try_recv() {
break (read, Ok(sendit));
}
match buff_sender.send_blocking(sendit) {
Ok(()) => {
continue 'reading;
}
Err(SendError(vec)) => {
warn!("Unable to send input");
sendit = vec;
}
}
}
}
};
}));
Self {
stop_sender,
buff_receiver,
join_handle,
buffer: vec![],
}
}
}
impl<R> AsyncRead for AsyncReader<R> {
fn poll_read(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Poll::Ready(loop {
if !self.buffer.is_empty() {
let len = buf.len().min(self.buffer.len());
buf[0..len].copy_from_slice(&self.buffer[0..len]);
if len == self.buffer.len() {
self.buffer.clear();
} else {
self.buffer = self.buffer.split_off(len);
}
break Ok(len);
}
if let Some(buf) = ready!(self.buff_receiver.poll_next(cx)) {
self.buffer = buf;
} else {
break Ok(0);
}
})
}
}
impl<R> Drop for AsyncReader<R> {
fn drop(&mut self) {
trace!("closing reader");
if let Some(join_handle) = self.join_handle.take() {
self.stop_sender
.send_blocking(())
.unwrap_or_else(|_| warn!("could not stop reader"));
trace!("stopped reader");
thread::sleep(Duration::from_millis(10));
if !join_handle.is_finished() {
warn!("abandoned the reader");
return;
}
match join_handle.join() {
Ok((_r, Ok(unread))) if unread.is_empty() => {}
Ok((_r, Ok(unread))) => {
warn!("unread data: {unread:?}")
}
Ok((_r, Err(e))) => {
warn!("reader error on drop: {e:?}")
}
Err(e) => warn!("could not join reader thread - {e:?}"),
}
trace!("closed reader");
}
}
}