X-Git-Url: https://code.octet-stream.net/m17rt/blobdiff_plain/2c7d53c113f4e19f24c928b2c5eca1c3f6f799af..5be3b9f857eefe983fbadae517a25da05b8b8982:/m17app/src/util/out_buffer.rs diff --git a/m17app/src/util/out_buffer.rs b/m17app/src/util/out_buffer.rs new file mode 100644 index 0000000..c24e0a9 --- /dev/null +++ b/m17app/src/util/out_buffer.rs @@ -0,0 +1,64 @@ +//! Buffer between `read()` calls + +use std::{ + io::{self, ErrorKind, Read}, + sync::{mpsc::Receiver, Arc, Mutex}, +}; + +#[derive(Clone)] +struct PartialOut { + output: Arc<[u8]>, + idx: usize, +} + +/// Buffer binary chunks from an MPSC receiver, feeding arbitrary chunks to `read()` calls. +/// +/// Can be cloned, but should only be read from once at a time. +#[derive(Clone)] +pub struct OutBuffer { + rx: Arc>>>, + partial_out: Arc>>, +} + +impl OutBuffer { + pub fn new(rx: Receiver>) -> Self { + Self { + rx: Arc::new(Mutex::new(rx)), + partial_out: Arc::new(Mutex::new(None)), + } + } +} + +impl Read for OutBuffer { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + { + let mut partial_out = self.partial_out.lock().unwrap(); + if let Some(partial) = partial_out.as_mut() { + let remaining = partial.output.len() - partial.idx; + let to_write = remaining.min(buf.len()); + buf[0..to_write] + .copy_from_slice(&partial.output[partial.idx..(partial.idx + to_write)]); + if to_write == remaining { + *partial_out = None; + } else { + partial.idx += to_write; + } + return Ok(to_write); + } + } + let output = { + let rx = self.rx.lock().unwrap(); + rx.recv() + .map_err(|s| io::Error::new(ErrorKind::Other, format!("{:?}", s)))? + }; + let to_write = output.len().min(buf.len()); + buf[0..to_write].copy_from_slice(&output[0..to_write]); + if to_write != output.len() { + *self.partial_out.lock().unwrap() = Some(PartialOut { + output, + idx: to_write, + }) + } + Ok(to_write) + } +}