#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Kind {
Ops = 0,
Hello = 1,
}
impl Kind {
pub const fn as_byte(self) -> u8 {
self as u8
}
pub const fn from_byte(byte: u8) -> Option<Self> {
match byte {
0 => Some(Kind::Ops),
1 => Some(Kind::Hello),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct ProtocolVersion(pub u32);
impl ProtocolVersion {
pub const UNKNOWN: ProtocolVersion = ProtocolVersion(0);
pub const fn agrees_with(self, other: ProtocolVersion) -> bool {
self.0 == 0 || other.0 == 0 || self.0 == other.0
}
}
pub fn split(frame: &[u8]) -> Option<(u8, &[u8])> {
frame.split_first().map(|(kind, body)| (*kind, body))
}
pub fn begin(kind: Kind, buf: &mut Vec<u8>) {
buf.clear();
buf.push(kind.as_byte());
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_frame_is_one_tag_byte_and_a_body() {
let mut buf = Vec::new();
begin(Kind::Ops, &mut buf);
buf.extend_from_slice(b"body");
assert_eq!(buf.len(), 5, "one byte of framing, whatever the codec");
let (kind, body) = split(&buf).expect("a non-empty frame splits");
assert_eq!(Kind::from_byte(kind), Some(Kind::Ops));
assert_eq!(body, b"body");
}
#[test]
fn an_unknown_kind_is_skippable_rather_than_fatal() {
assert_eq!(Kind::from_byte(200), None);
let frame = [200u8, 1, 2, 3];
let (kind, body) = split(&frame).expect("still a well-formed frame");
assert_eq!(Kind::from_byte(kind), None, "unknown, so the frame is skipped");
assert_eq!(body, &[1, 2, 3], "and its body is still delimited");
}
#[test]
fn a_hello_dispatches_to_a_different_body_than_ops() {
assert_eq!(Kind::from_byte(Kind::Hello.as_byte()), Some(Kind::Hello));
assert_ne!(Kind::Ops.as_byte(), Kind::Hello.as_byte());
}
#[test]
fn an_undeclared_version_agrees_with_everything() {
assert!(ProtocolVersion::UNKNOWN.agrees_with(ProtocolVersion(7)));
assert!(ProtocolVersion(7).agrees_with(ProtocolVersion::UNKNOWN));
assert!(ProtocolVersion(7).agrees_with(ProtocolVersion(7)));
assert!(!ProtocolVersion(7).agrees_with(ProtocolVersion(8)));
}
#[test]
fn an_empty_frame_is_malformed() {
assert_eq!(split(&[]), None);
}
}