mod defaults;
mod header;
pub use header::*;
pub type DefaultProtocolContext = ();
pub const fn default_payload_context() -> DefaultProtocolContext {}
pub trait ProtocolSchema {
type Context<'a>;
const MAX_PAYLOAD_LEN: u32 = crate::DEFAULT_MAX_PAYLOAD_LEN;
const MAX_PACKET_LEN: u64 = crate::DEFAULT_MAX_PACKET_LEN;
const INITIAL_PACKET_BUFFER_CAPACITY: usize = crate::DEFAULT_INITIAL_PACKET_BUFFER_CAPACITY;
}
impl ProtocolSchema for () {
type Context<'a> = ();
}
pub enum EncodedPayload<'a> {
Borrowed(&'a [u8]),
Owned(Vec<u8>),
}
impl EncodedPayload<'_> {
pub fn as_slice(&self) -> &[u8] {
match self {
Self::Borrowed(bytes) => bytes,
Self::Owned(bytes) => bytes.as_slice(),
}
}
pub fn len(&self) -> usize {
self.as_slice().len()
}
pub fn is_empty(&self) -> bool {
self.as_slice().is_empty()
}
}
pub trait PayloadHooks {
fn before_encode(&mut self) -> std::io::Result<()> {
Ok(())
}
fn after_decode(&mut self) -> std::io::Result<()> {
Ok(())
}
}
pub trait PayloadEncode: PayloadHooks + ProtocolSchema {
fn encode(&self, ctx: &mut Self::Context<'_>) -> std::io::Result<Vec<u8>>;
}
pub trait PayloadEncodeReferred: ProtocolSchema {
fn encode(&self, ctx: &mut Self::Context<'_>) -> std::io::Result<Option<&[u8]>>;
}
pub trait PayloadEncoded: PayloadEncode + PayloadEncodeReferred {
fn encoded(&self, ctx: &mut Self::Context<'_>) -> std::io::Result<EncodedPayload<'_>> {
if let Some(bytes) = PayloadEncodeReferred::encode(self, ctx)? {
Ok(EncodedPayload::Borrowed(bytes))
} else {
Ok(EncodedPayload::Owned(PayloadEncode::encode(self, ctx)?))
}
}
}
impl<T> PayloadEncoded for T where T: PayloadEncode + PayloadEncodeReferred {}
pub trait PayloadDecode<T>: PayloadHooks + ProtocolSchema {
fn decode(buf: &[u8], ctx: &mut Self::Context<'_>) -> std::io::Result<T>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encoded_payload_is_empty_for_borrowed_and_owned() {
let empty_borrowed = EncodedPayload::Borrowed(&[]);
assert!(empty_borrowed.is_empty());
let non_empty_borrowed = EncodedPayload::Borrowed(&[1]);
assert!(!non_empty_borrowed.is_empty());
let empty_owned = EncodedPayload::Owned(Vec::new());
assert!(empty_owned.is_empty());
let non_empty_owned = EncodedPayload::Owned(vec![1, 2, 3]);
assert!(!non_empty_owned.is_empty());
}
#[derive(Default)]
struct NoopHooksPayload;
impl ProtocolSchema for NoopHooksPayload {
type Context<'a> = ();
}
impl PayloadHooks for NoopHooksPayload {}
#[test]
fn default_payload_hooks_are_noop_ok() {
let mut payload = NoopHooksPayload;
assert!(payload.before_encode().is_ok());
assert!(payload.after_decode().is_ok());
}
}