bubbles 4.1.0

Bubble integration server for powder diffraction
use crate::session::{BubbleState, ClientRequest};
use bytes::{BufMut, BytesMut};
use std::io;
use tokio_util::codec::{Decoder, Encoder};

pub struct BubbleCodec;

impl Decoder for BubbleCodec {
    type Item = ClientRequest;
    type Error = io::Error;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        let end = src.search_message_end()?;
        if end == 0 {
            return Ok(None);
        }
        let buf = src.split_to(end);
        Ok(Some(serde_json::from_slice::<ClientRequest>(&buf)?))
    }
}

impl Encoder<BubbleState> for BubbleCodec {
    type Error = io::Error;

    fn encode(&mut self, msg: BubbleState, dst: &mut BytesMut) -> Result<(), Self::Error> {
        let mut msg = serde_json::to_string(&msg).unwrap();
        msg.push_str("\r\n");
        dst.put(msg.as_bytes());
        Ok(())
    }
}

trait MessageEnd {
    fn search_message_end(&self) -> io::Result<usize>;
}

impl MessageEnd for BytesMut {
    fn search_message_end(&self) -> io::Result<usize> {
        for (mut pos, byte) in self.iter().enumerate() {
            if byte != &('\r' as u8) {
                continue;
            }
            pos += 1;
            return if self.len() <= pos {
                Ok(0)
            } else if self[pos] != '\n' as u8 {
                Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    "bad bytes in the client JSON request",
                ))
            } else {
                Ok(pos)
            };
        }
        Ok(0)
    }
}