rust-mqtt 0.5.1

MQTT client for embedded and non-embedded environments
Documentation
use core::cmp::min;

use crate::eio::{self, ErrorType, Write};

pub struct SliceWriter<'a> {
    slice: &'a mut [u8],
    index: usize,
}

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SliceWriterError;
impl core::fmt::Display for SliceWriterError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "{self:?}")
    }
}
impl core::error::Error for SliceWriterError {
    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
        None
    }
}
impl eio::Error for SliceWriterError {
    fn kind(&self) -> eio::ErrorKind {
        eio::ErrorKind::Other
    }
}
impl ErrorType for SliceWriter<'_> {
    type Error = SliceWriterError;
}
impl Write for SliceWriter<'_> {
    async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
        let left = self.slice.len().saturating_sub(self.index);
        let writing = min(left, buf.len());
        let end = self.index + writing;
        if writing == 0 {
            return Ok(0);
        }

        let dest = &mut self.slice[self.index..end];
        let src = &buf[..writing];

        dest.clone_from_slice(src);
        self.index = end;
        Ok(writing)
    }

    async fn flush(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

impl<'a> SliceWriter<'a> {
    pub fn new(slice: &'a mut [u8]) -> Self {
        Self { slice, index: 0 }
    }

    pub fn written(&self) -> usize {
        self.index
    }
}

#[cfg(test)]
mod unit {
    use tokio_test::assert_ok;

    use crate::{eio::Write, test::write::SliceWriter};

    #[tokio::test]
    #[test_log::test]
    async fn writes_in_one() {
        let mut buf = [0u8; 5];
        {
            let mut writer = SliceWriter::new(&mut buf);

            let n = assert_ok!(writer.write(b"hello").await);
            assert_eq!(n, 5);

            let n = assert_ok!(writer.write(b"again").await);
            assert_eq!(n, 0);
        }

        assert_eq!(&buf, b"hello");
    }

    #[tokio::test]
    #[test_log::test]
    async fn writes_in_chunks() {
        let mut buf = [0u8; 2];
        {
            let mut writer = SliceWriter::new(&mut buf);

            let n1 = assert_ok!(writer.write(b"a").await);
            assert_eq!(n1, 1);

            let n2 = assert_ok!(writer.write(b"b").await);
            assert_eq!(n2, 1);

            let n3 = assert_ok!(writer.write(b"c").await);
            assert_eq!(n3, 0);
        }

        assert_eq!(&buf, b"ab");
    }

    #[tokio::test]
    #[test_log::test]
    async fn partial_write_when_not_enough_space() {
        let mut buf = [0u8; 3];
        {
            let mut writer = SliceWriter::new(&mut buf);

            let n1 = assert_ok!(writer.write(b"ab").await);
            assert_eq!(n1, 2);

            let n2 = assert_ok!(writer.write(b"xyz").await);
            assert_eq!(n2, 1);
        }

        assert_eq!(&buf, b"abx");
    }
}