use glaredb_error::{DbError, Result, ResultExt};
use prost::Message;
#[derive(Debug)]
pub struct PackedEncoder<'a> {
buf: &'a mut Vec<u8>,
}
impl<'a> PackedEncoder<'a> {
pub fn new(buf: &'a mut Vec<u8>) -> Self {
PackedEncoder { buf }
}
pub fn encode_next<M: Message>(&mut self, msg: &M) -> Result<()> {
let msg_len = msg.encoded_len();
let mut buf_start = self.buf.len();
self.buf.resize(self.buf.len() + 8 + msg_len, 0);
self.buf[buf_start..buf_start + 8].copy_from_slice(&(msg_len as u64).to_le_bytes());
buf_start += 8;
let mut buf = &mut self.buf[buf_start..buf_start + msg_len];
msg.encode(&mut buf).context("failed to encode message")?;
Ok(())
}
}
#[derive(Debug)]
pub struct PackedDecoder<'a> {
buf: &'a [u8],
n: usize,
}
impl<'a> PackedDecoder<'a> {
pub fn new(buf: &'a [u8]) -> Self {
PackedDecoder { buf, n: 0 }
}
pub fn decode_next<M: Message + Default>(&mut self) -> Result<M> {
let msg_len_buf: [u8; 8] = self
.buf
.get(self.n..self.n + 8)
.ok_or_else(|| DbError::new("buffer too small to contain message"))?
.try_into()
.unwrap();
let msg_len = u64::from_le_bytes(msg_len_buf) as usize;
self.n += 8;
let buf = &self.buf[self.n..self.n + msg_len];
let msg = M::decode(buf).context("failed to decode message")?;
self.n += msg_len;
Ok(msg)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generated::schema::{DataType, DecimalTypeMeta, EmptyMeta, Field, data_type};
#[test]
fn single_message() {
let field = Field {
name: "hello".to_string(),
datatype: Some(DataType {
value: Some(data_type::Value::TypeInt16(EmptyMeta {})),
}),
nullable: true,
};
let mut buf = Vec::new();
{
let mut encoder = PackedEncoder::new(&mut buf);
encoder.encode_next(&field).unwrap();
}
let mut decoder = PackedDecoder::new(&buf);
let msg: Field = decoder.decode_next().unwrap();
assert_eq!(field, msg);
assert_eq!("hello", msg.name);
}
#[test]
fn multiple_messages() {
let field = Field {
name: "hello".to_string(),
datatype: Some(DataType {
value: Some(data_type::Value::TypeInt16(EmptyMeta {})),
}),
nullable: true,
};
let decimal_meta = DecimalTypeMeta {
precision: 19,
scale: 8,
};
let mut buf = Vec::new();
{
let mut encoder = PackedEncoder::new(&mut buf);
encoder.encode_next(&field).unwrap();
encoder.encode_next(&decimal_meta).unwrap();
}
let mut decoder = PackedDecoder::new(&buf);
let msg1: Field = decoder.decode_next().unwrap();
let msg2: DecimalTypeMeta = decoder.decode_next().unwrap();
assert_eq!(field, msg1);
assert_eq!(decimal_meta, msg2);
assert_eq!(19, msg2.precision);
}
}