Files
smartdb/rust/crates/rustdb-wire/src/codec.rs

50 lines
1.4 KiB
Rust

use bytes::{Buf, BytesMut};
use tokio_util::codec::{Decoder, Encoder};
use crate::error::WireError;
use crate::parser::{parse_message, ParsedCommand};
/// Tokio codec for framing wire protocol messages on a TCP stream.
///
/// The wire protocol is naturally length-prefixed:
/// the first 4 bytes of each message contain the total message length.
pub struct WireCodec;
impl Decoder for WireCodec {
type Item = ParsedCommand;
type Error = WireError;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if src.len() < 4 {
return Ok(None);
}
// Peek at message length
let msg_len = i32::from_le_bytes([src[0], src[1], src[2], src[3]]) as usize;
if src.len() < msg_len {
// Reserve space for the rest of the message
src.reserve(msg_len - src.len());
return Ok(None);
}
match parse_message(src)? {
Some((cmd, bytes_consumed)) => {
src.advance(bytes_consumed);
Ok(Some(cmd))
}
None => Ok(None),
}
}
}
/// Encoder for raw byte responses (already serialized by the command handlers).
impl Encoder<Vec<u8>> for WireCodec {
type Error = WireError;
fn encode(&mut self, item: Vec<u8>, dst: &mut BytesMut) -> Result<(), Self::Error> {
dst.extend_from_slice(&item);
Ok(())
}
}