#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum Head {
Nil,
Bool(bool),
Uint(u64),
Int(i64),
F32(f32),
F64(f64),
Str(u32),
Bin(u32),
Array(u32),
Map(u32),
Ext(i8, u32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum HeadError {
Incomplete,
Reserved,
}
#[inline(always)]
fn read<const N: usize>(input: &[u8], offset: usize) -> Result<[u8; N], HeadError> {
match input.get(offset..offset + N) {
Some(bytes) => Ok(bytes.try_into().unwrap()),
None => Err(HeadError::Incomplete),
}
}
#[inline(always)]
fn len8(input: &[u8]) -> Result<u32, HeadError> {
Ok(u32::from(read::<1>(input, 1)?[0]))
}
#[inline(always)]
fn len16(input: &[u8]) -> Result<u32, HeadError> {
Ok(u32::from(u16::from_be_bytes(read(input, 1)?)))
}
#[inline(always)]
fn len32(input: &[u8]) -> Result<u32, HeadError> {
Ok(u32::from_be_bytes(read(input, 1)?))
}
#[inline(always)]
fn int(value: i64) -> Head {
if value < 0 {
Head::Int(value)
} else {
Head::Uint(value as u64)
}
}
#[inline(always)]
pub(crate) fn decode_head(input: &[u8]) -> Result<(Head, usize), HeadError> {
let Some(&byte) = input.first() else {
return Err(HeadError::Incomplete);
};
Ok(match byte {
0x00..=0x7f => (Head::Uint(u64::from(byte)), 1),
0x80..=0x8f => (Head::Map(u32::from(byte & 0x0f)), 1),
0x90..=0x9f => (Head::Array(u32::from(byte & 0x0f)), 1),
0xa0..=0xbf => (Head::Str(u32::from(byte & 0x1f)), 1),
0xc0 => (Head::Nil, 1),
0xc1 => return Err(HeadError::Reserved),
0xc2 => (Head::Bool(false), 1),
0xc3 => (Head::Bool(true), 1),
0xc4 => (Head::Bin(len8(input)?), 2),
0xc5 => (Head::Bin(len16(input)?), 3),
0xc6 => (Head::Bin(len32(input)?), 5),
0xc7 => (Head::Ext(read::<1>(input, 2)?[0] as i8, len8(input)?), 3),
0xc8 => (Head::Ext(read::<1>(input, 3)?[0] as i8, len16(input)?), 4),
0xc9 => (Head::Ext(read::<1>(input, 5)?[0] as i8, len32(input)?), 6),
0xca => (Head::F32(f32::from_be_bytes(read(input, 1)?)), 5),
0xcb => (Head::F64(f64::from_be_bytes(read(input, 1)?)), 9),
0xcc => (Head::Uint(u64::from(read::<1>(input, 1)?[0])), 2),
0xcd => (
Head::Uint(u64::from(u16::from_be_bytes(read(input, 1)?))),
3,
),
0xce => (
Head::Uint(u64::from(u32::from_be_bytes(read(input, 1)?))),
5,
),
0xcf => (Head::Uint(u64::from_be_bytes(read(input, 1)?)), 9),
0xd0 => (int(i64::from(read::<1>(input, 1)?[0] as i8)), 2),
0xd1 => (int(i64::from(i16::from_be_bytes(read(input, 1)?))), 3),
0xd2 => (int(i64::from(i32::from_be_bytes(read(input, 1)?))), 5),
0xd3 => (int(i64::from_be_bytes(read(input, 1)?)), 9),
0xd4..=0xd8 => {
let len = 1 << (byte - 0xd4);
(Head::Ext(read::<1>(input, 1)?[0] as i8, len), 2)
}
0xd9 => (Head::Str(len8(input)?), 2),
0xda => (Head::Str(len16(input)?), 3),
0xdb => (Head::Str(len32(input)?), 5),
0xdc => (Head::Array(len16(input)?), 3),
0xdd => (Head::Array(len32(input)?), 5),
0xde => (Head::Map(len16(input)?), 3),
0xdf => (Head::Map(len32(input)?), 5),
0xe0..=0xff => (Head::Int(i64::from(byte as i8)), 1),
})
}
#[test]
fn test_decode_head() {
assert_eq!(decode_head(&[0x7f]), Ok((Head::Uint(127), 1)));
assert_eq!(decode_head(&[0xe0]), Ok((Head::Int(-32), 1)));
assert_eq!(decode_head(&[0xd0, 0x05]), Ok((Head::Uint(5), 2)));
assert_eq!(decode_head(&[0xd0, 0xff]), Ok((Head::Int(-1), 2)));
assert_eq!(decode_head(&[0xc7, 0x03, 0x07]), Ok((Head::Ext(7, 3), 3)));
assert_eq!(
decode_head(&[0xc8, 0x01, 0x00, 0xff]),
Ok((Head::Ext(-1, 256), 4))
);
assert_eq!(decode_head(&[0xd8, 0x05]), Ok((Head::Ext(5, 16), 2)));
assert_eq!(decode_head(&[0xc1]), Err(HeadError::Reserved));
assert_eq!(decode_head(&[]), Err(HeadError::Incomplete));
assert_eq!(decode_head(&[0xc7, 0x03]), Err(HeadError::Incomplete));
assert_eq!(decode_head(&[0xcf, 0, 0]), Err(HeadError::Incomplete));
}