rustradio 0.17.2

Software defined radio library
Documentation
use std::io::Write;

use crate::block::{Block, BlockRet};
use crate::stream::ReadStream;
use crate::{Result, Sample};

/// Arbitrary writer sink.
#[derive(rustradio_macros::Block)]
#[rustradio(crate)]
pub struct WriterSink<T: Sample> {
    writer: Box<dyn Write + Send>,
    #[rustradio(in)]
    src: ReadStream<T>,

    #[rustradio(default)]
    buf: Vec<u8>,
}

impl<T: Sample> WriterSink<T> {
    pub fn new<R: Write + Send + 'static>(src: ReadStream<T>, writer: R) -> Self {
        Self {
            writer: Box::new(writer),
            src,
            buf: Vec::new(),
        }
    }
}

impl<T> Block for WriterSink<T>
where
    T: Sample<Type = T> + std::fmt::Debug,
{
    fn work(&mut self) -> Result<BlockRet<'_>> {
        loop {
            if !self.buf.is_empty() {
                let rc = self.writer.write(&self.buf)?;
                if rc == 0 {
                    return Err(
                        std::io::Error::new(std::io::ErrorKind::WriteZero, "WriterSink").into(),
                    );
                }
                self.buf.drain(..rc);
                if !self.buf.is_empty() {
                    return Ok(BlockRet::Pending);
                }
                continue;
            }

            let (i, _) = self.src.read_buf()?;
            if i.is_empty() {
                return Ok(BlockRet::WaitForStream(&self.src, 1));
            }
            for s in i.iter().map(|x| x.serialize()) {
                self.buf.extend(s);
            }
            let n = i.len();
            i.consume(n);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::blocks::VectorSource;
    use std::io::Cursor;
    use std::sync::{Arc, Mutex};

    #[derive(Clone)]
    struct Fake {
        cur: Arc<Mutex<Cursor<Vec<u8>>>>,
    }
    impl Default for Fake {
        fn default() -> Self {
            Self {
                cur: Arc::new(Mutex::new(Cursor::new(Vec::new()))),
            }
        }
    }

    impl Write for Fake {
        fn write(&mut self, b: &[u8]) -> std::result::Result<usize, std::io::Error> {
            self.cur.lock().unwrap().write(b)
        }
        fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
            self.cur.lock().unwrap().flush()
        }
    }

    #[test]
    fn writer_sink() -> Result<()> {
        let (mut b, prev) = VectorSource::new(b"hello world".to_vec());
        b.work()?;
        let fake = Fake::default();
        let mut b = WriterSink::<u8>::new(prev, fake.clone());
        b.work()?;
        assert_eq!(fake.cur.lock().unwrap().get_ref(), b"hello world");
        Ok(())
    }
}