use bytes::Bytes;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LogOutput {
StdIn {
message: Bytes,
},
StdOut {
message: Bytes,
},
StdErr {
message: Bytes,
},
Console {
message: Bytes,
},
}
pub struct LogFrameDecoder {
buffer: Vec<u8>,
cursor: usize,
}
impl LogFrameDecoder {
#[must_use]
pub fn new() -> Self {
Self {
buffer: Vec::new(),
cursor: 0,
}
}
pub fn feed(&mut self, chunk: &[u8]) {
self.buffer.extend_from_slice(chunk);
}
#[must_use]
pub fn decode(&mut self) -> Option<LogOutput> {
const HEADER_SIZE: usize = 8;
if self.buffer.len() - self.cursor < HEADER_SIZE {
return None;
}
let header = &self.buffer[self.cursor..self.cursor + HEADER_SIZE];
let stream_type = header[0];
let length = u32::from_be_bytes([header[4], header[5], header[6], header[7]]) as usize;
if self.buffer.len() - self.cursor < HEADER_SIZE + length {
return None;
}
let payload_start = self.cursor + HEADER_SIZE;
let payload = Bytes::copy_from_slice(&self.buffer[payload_start..payload_start + length]);
self.cursor = payload_start + length;
match stream_type {
0 => Some(LogOutput::StdIn { message: payload }),
1 => Some(LogOutput::StdOut { message: payload }),
2 => Some(LogOutput::StdErr { message: payload }),
3 => Some(LogOutput::Console { message: payload }),
_ => {
None
}
}
}
pub fn compact(&mut self) {
if self.cursor > 0 {
self.buffer.drain(..self.cursor);
self.cursor = 0;
}
}
#[must_use]
pub fn buffered_len(&self) -> usize {
self.buffer.len() - self.cursor
}
#[must_use]
pub fn next_frame_len(&self) -> Option<usize> {
let header = self.buffer.get(self.cursor..self.cursor + 8)?;
Some(u32::from_be_bytes([header[4], header[5], header[6], header[7]]) as usize)
}
}
impl Default for LogFrameDecoder {
fn default() -> Self {
Self::new()
}
}