You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
distant/tests/common/utils/reader.rs

104 lines
3.2 KiB
Rust

use std::io::{BufRead, BufReader, Read};
use std::sync::mpsc;
use std::time::{Duration, Instant};
use std::{io, thread};
pub struct ThreadedReader {
#[allow(dead_code)]
handle: thread::JoinHandle<io::Result<()>>,
rx: mpsc::Receiver<String>,
}
impl ThreadedReader {
pub fn new<R>(reader: R) -> Self
where
R: Read + Send + 'static,
{
let (tx, rx) = mpsc::channel();
let handle = thread::spawn(move || {
let mut reader = BufReader::new(reader);
let mut line = String::new();
loop {
match reader.read_line(&mut line) {
Ok(0) => break Ok(()),
Ok(_) => {
// Consume the line and create an empty line to
// be filled in next time
let line2 = line;
line = String::new();
if let Err(line) = tx.send(line2) {
return Err(io::Error::new(
io::ErrorKind::Other,
format!(
"Failed to pass along line because channel closed! Line: '{}'",
line.0
),
));
}
}
Err(x) => return Err(x),
}
}
});
Self { handle, rx }
}
/// Tries to read the next line if available
pub fn try_read_line(&mut self) -> Option<String> {
self.rx.try_recv().ok()
}
/// Reads the next line, waiting for at minimum "timeout"
pub fn try_read_line_timeout(&mut self, timeout: Duration) -> Option<String> {
let start_time = Instant::now();
let mut checked_at_least_once = false;
while !checked_at_least_once || start_time.elapsed() < timeout {
if let Some(line) = self.try_read_line() {
return Some(line);
}
checked_at_least_once = true;
}
None
}
/// Reads the next line, waiting for at minimum "timeout" before panicking
pub fn read_line_timeout(&mut self, timeout: Duration) -> String {
let start_time = Instant::now();
let mut checked_at_least_once = false;
while !checked_at_least_once || start_time.elapsed() < timeout {
if let Some(line) = self.try_read_line() {
return line;
}
checked_at_least_once = true;
}
panic!("Reached timeout of {:?}", timeout);
}
/// Reads the next line, waiting for at minimum default timeout before panicking
#[allow(dead_code)]
pub fn read_line_default_timeout(&mut self) -> String {
self.read_line_timeout(Self::default_timeout())
}
/// Creates a new duration representing a default timeout for the threaded reader
pub fn default_timeout() -> Duration {
Duration::from_millis(250)
}
/// Waits for reader to shut down, returning the result
#[allow(dead_code)]
pub fn wait(self) -> io::Result<()> {
match self.handle.join() {
Ok(x) => x,
Err(x) => std::panic::resume_unwind(x),
}
}
}