use rkyv::api::high::{HighDeserializer, HighSerializer, HighValidator};
use rkyv::ser::allocator::ArenaHandle;
use rkyv::util::AlignedVec;
use rkyv::{Archive, Deserialize, Serialize, rancor};
use std::io::{BufReader, BufWriter, Read, Write};
use thiserror::Error;
pub const MAX_FRAME_SIZE: usize = 16 * 1024 * 1024;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum FrameError {
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Serialization error: {0}")]
Serialization(String),
#[error("Deserialization error: {0}")]
Deserialization(String),
#[error("Frame too large: {size} bytes (max {max} bytes)")]
FrameTooLarge {
size: usize,
max: usize,
},
#[error("Invalid frame: {0}")]
InvalidFrame(String),
#[error("End of stream")]
EndOfStream,
}
pub fn write_frame<W, T>(writer: &mut BufWriter<W>, message: &T) -> Result<(), FrameError>
where
W: Write,
T: for<'a> Serialize<HighSerializer<AlignedVec, ArenaHandle<'a>, rancor::Error>>,
{
let bytes = rkyv::to_bytes::<rancor::Error>(message)
.map_err(|e| FrameError::Serialization(e.to_string()))?;
let len = bytes.len();
if len > MAX_FRAME_SIZE {
return Err(FrameError::FrameTooLarge {
size: len,
max: MAX_FRAME_SIZE,
});
}
writer.write_all(&(len as u32).to_le_bytes())?;
writer.write_all(&bytes)?;
writer.flush()?;
Ok(())
}
pub fn read_frame<R, T>(reader: &mut BufReader<R>) -> Result<T, FrameError>
where
R: Read,
T: Archive,
T::Archived: for<'a> rkyv::bytecheck::CheckBytes<HighValidator<'a, rancor::Error>>
+ Deserialize<T, HighDeserializer<rancor::Error>>,
{
let mut len_buf = [0u8; 4];
match reader.read_exact(&mut len_buf) {
Ok(()) => {}
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
return Err(FrameError::EndOfStream);
}
Err(e) => return Err(FrameError::Io(e)),
}
let len = u32::from_le_bytes(len_buf) as usize;
if len > MAX_FRAME_SIZE {
return Err(FrameError::FrameTooLarge {
size: len,
max: MAX_FRAME_SIZE,
});
}
if len == 0 {
return Err(FrameError::InvalidFrame("zero-length frame".to_string()));
}
let mut buf = AlignedVec::<16>::with_capacity(len);
buf.resize(len, 0);
reader.read_exact(&mut buf)?;
let value: T = rkyv::from_bytes::<T, rancor::Error>(&buf)
.map_err(|e| FrameError::Deserialization(e.to_string()))?;
Ok(value)
}
pub struct FrameWriter<W: Write> {
writer: BufWriter<W>,
}
impl<W: Write> FrameWriter<W> {
pub fn new(writer: W) -> Self {
Self {
writer: BufWriter::with_capacity(64 * 1024, writer), }
}
pub fn write<T>(&mut self, message: &T) -> Result<(), FrameError>
where
T: for<'a> Serialize<HighSerializer<AlignedVec, ArenaHandle<'a>, rancor::Error>>,
{
write_frame(&mut self.writer, message)
}
pub fn flush(&mut self) -> Result<(), FrameError> {
self.writer.flush()?;
Ok(())
}
pub fn inner_mut(&mut self) -> &mut BufWriter<W> {
&mut self.writer
}
pub fn into_inner(self) -> BufWriter<W> {
self.writer
}
}
pub struct FrameReader<R: Read> {
reader: BufReader<R>,
}
impl<R: Read> FrameReader<R> {
pub fn new(reader: R) -> Self {
Self {
reader: BufReader::with_capacity(64 * 1024, reader), }
}
pub fn read<T>(&mut self) -> Result<T, FrameError>
where
T: Archive,
T::Archived: for<'a> rkyv::bytecheck::CheckBytes<HighValidator<'a, rancor::Error>>
+ Deserialize<T, HighDeserializer<rancor::Error>>,
{
read_frame(&mut self.reader)
}
pub fn has_buffered_data(&self) -> bool {
!self.reader.buffer().is_empty()
}
pub fn inner_mut(&mut self) -> &mut BufReader<R> {
&mut self.reader
}
pub fn into_inner(self) -> BufReader<R> {
self.reader
}
}
#[cfg(test)]
mod tests {
use super::*;
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
use std::io::Cursor;
#[derive(Debug, Clone, PartialEq, Archive, RkyvSerialize, RkyvDeserialize)]
struct TestMessage {
value: u64,
text: String,
}
#[test]
fn test_roundtrip() {
let original = TestMessage {
value: 42,
text: "hello world".to_string(),
};
let mut buffer = Vec::new();
{
let mut writer = FrameWriter::new(&mut buffer);
writer.write(&original).unwrap();
}
let mut reader = FrameReader::new(Cursor::new(buffer));
let decoded: TestMessage = reader.read().unwrap();
assert_eq!(original, decoded);
}
#[test]
fn test_multiple_messages() {
let messages = vec![
TestMessage {
value: 1,
text: "first".to_string(),
},
TestMessage {
value: 2,
text: "second".to_string(),
},
TestMessage {
value: 3,
text: "third".to_string(),
},
];
let mut buffer = Vec::new();
{
let mut writer = FrameWriter::new(&mut buffer);
for msg in &messages {
writer.write(msg).unwrap();
}
}
let mut reader = FrameReader::new(Cursor::new(buffer));
for expected in &messages {
let decoded: TestMessage = reader.read().unwrap();
assert_eq!(expected, &decoded);
}
}
#[test]
fn test_end_of_stream() {
let buffer: Vec<u8> = Vec::new();
let mut reader = FrameReader::new(Cursor::new(buffer));
let result: Result<TestMessage, _> = reader.read();
assert!(matches!(result, Err(FrameError::EndOfStream)));
}
}