use integer_encoding::VarInt;
use std::{collections::VecDeque, rc::Rc};
pub struct MessageDisassembler {
messages: VecDeque<(Rc<Vec<u8>>, usize, bool)>,
}
impl MessageDisassembler {
pub fn new() -> Self {
Self {
messages: VecDeque::new(),
}
}
pub fn push(&mut self, message: Rc<Vec<u8>>) {
if message.is_empty() {
return;
}
self.messages.push_back((message, 0, false));
}
pub fn pop(&mut self, mut max_size: usize) -> Option<Vec<u8>> {
let mut payload = Vec::with_capacity(max_size);
while let Some((message, offset, wrote_size)) = self.messages.front_mut() {
if !*wrote_size {
let mut encoded = [0u8; 5];
let size_len = message.len().encode_var(&mut encoded);
if max_size < size_len {
break;
}
payload.extend_from_slice(&encoded[..size_len]);
max_size -= size_len;
*wrote_size = true;
}
let remaining_msg = message.len() - *offset;
if max_size == 0 {
break;
} else if max_size > remaining_msg {
payload.extend_from_slice(&message[*offset..]);
max_size -= remaining_msg;
self.messages.pop_front();
} else if max_size < remaining_msg {
payload.extend_from_slice(&message[*offset..*offset + max_size]);
*offset += max_size;
break;
} else {
payload.extend_from_slice(&message[*offset..]);
self.messages.pop_front();
break;
}
}
if payload.is_empty() {
None
} else {
Some(payload)
}
}
}