#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum CodecTag {
Raw = 0,
Structural = 1,
}
impl CodecTag {
pub fn from_byte(b: u8) -> Option<Self> {
match b {
0 => Some(CodecTag::Raw),
1 => Some(CodecTag::Structural),
_ => None,
}
}
pub fn as_byte(self) -> u8 {
self as u8
}
}
pub fn peek_tag(payload: &[u8]) -> Option<CodecTag> {
let first = *payload.first()?;
CodecTag::from_byte(first)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raw_tag_roundtrips() {
assert_eq!(CodecTag::Raw.as_byte(), 0);
assert_eq!(CodecTag::from_byte(0), Some(CodecTag::Raw));
}
#[test]
fn structural_tag_roundtrips() {
assert_eq!(CodecTag::Structural.as_byte(), 1);
assert_eq!(CodecTag::from_byte(1), Some(CodecTag::Structural));
}
#[test]
fn unknown_byte_returns_none() {
assert_eq!(CodecTag::from_byte(42), None);
assert_eq!(CodecTag::from_byte(255), None);
}
#[test]
fn peek_tag_former_msgpack_bytes_return_none() {
for b in 0x80u8..=0x8fu8 {
let payload = [b, 0x00];
assert_eq!(peek_tag(&payload), None, "byte {b:#04x} should be None");
}
assert_eq!(peek_tag(&[0xde, 0x00]), None);
assert_eq!(peek_tag(&[0xdf, 0x00]), None);
}
#[test]
fn peek_tag_detects_raw_tag() {
assert_eq!(peek_tag(&[0x00, 0x01, 0x02]), Some(CodecTag::Raw));
}
#[test]
fn peek_tag_detects_structural_tag() {
assert_eq!(peek_tag(&[0x01, 0x00]), Some(CodecTag::Structural));
}
#[test]
fn peek_tag_empty_returns_none() {
assert_eq!(peek_tag(&[]), None);
}
#[test]
fn peek_tag_unknown_byte_returns_none() {
assert_eq!(peek_tag(&[42]), None);
}
}