#![allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub enum MsgValue {
Nil,
Bool(bool),
Int(i64),
Float(f64),
Str(String),
Bin(Vec<u8>),
Array(Vec<MsgValue>),
Map(Vec<(MsgValue, MsgValue)>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum MsgError {
UnexpectedEnd,
UnknownFormat(u8),
InvalidUtf8,
LengthOverflow,
}
impl std::fmt::Display for MsgError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnexpectedEnd => write!(f, "unexpected end of buffer"),
Self::UnknownFormat(b) => write!(f, "unknown format byte: 0x{b:02x}"),
Self::InvalidUtf8 => write!(f, "invalid UTF-8 in string"),
Self::LengthOverflow => write!(f, "length field overflows usize"),
}
}
}
pub fn encode(val: &MsgValue, buf: &mut Vec<u8>) {
match val {
MsgValue::Nil => buf.push(0xc0),
MsgValue::Bool(true) => buf.push(0xc3),
MsgValue::Bool(false) => buf.push(0xc2),
MsgValue::Int(i) => {
if (0..=127).contains(i) {
buf.push(*i as u8);
} else {
buf.push(0xd3);
buf.extend_from_slice(&i.to_be_bytes());
}
}
MsgValue::Float(f) => {
buf.push(0xcb);
buf.extend_from_slice(&f.to_bits().to_be_bytes());
}
MsgValue::Str(s) => {
let bytes = s.as_bytes();
if bytes.len() <= 31 {
buf.push(0xa0 | bytes.len() as u8);
} else {
buf.push(0xd9);
buf.push(bytes.len() as u8);
}
buf.extend_from_slice(bytes);
}
MsgValue::Bin(b) => {
buf.push(0xc4);
buf.push(b.len() as u8);
buf.extend_from_slice(b);
}
MsgValue::Array(arr) => {
buf.push(0x90 | arr.len().min(15) as u8);
for item in arr {
encode(item, buf);
}
}
MsgValue::Map(map) => {
buf.push(0x80 | map.len().min(15) as u8);
for (k, v) in map {
encode(k, buf);
encode(v, buf);
}
}
}
}
pub fn encoded_size(val: &MsgValue) -> usize {
match val {
MsgValue::Nil | MsgValue::Bool(_) => 1,
MsgValue::Int(i) => {
if (0..=127).contains(i) {
1
} else {
9
}
}
MsgValue::Float(_) => 9,
MsgValue::Str(s) => 1 + s.len(),
MsgValue::Bin(b) => 2 + b.len(),
MsgValue::Array(a) => 1 + a.iter().map(encoded_size).sum::<usize>(),
MsgValue::Map(m) => {
1 + m
.iter()
.map(|(k, v)| encoded_size(k) + encoded_size(v))
.sum::<usize>()
}
}
}
pub fn buffers_equal(a: &[u8], b: &[u8]) -> bool {
a == b
}
pub fn array_len(val: &MsgValue) -> usize {
if let MsgValue::Array(arr) = val {
arr.len()
} else {
0
}
}
pub fn is_nil(val: &MsgValue) -> bool {
matches!(val, MsgValue::Nil)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_nil() {
let mut buf = vec![];
encode(&MsgValue::Nil, &mut buf);
assert_eq!(buf, &[0xc0]);
}
#[test]
fn test_encode_bool_true() {
let mut buf = vec![];
encode(&MsgValue::Bool(true), &mut buf);
assert_eq!(buf, &[0xc3]);
}
#[test]
fn test_encode_bool_false() {
let mut buf = vec![];
encode(&MsgValue::Bool(false), &mut buf);
assert_eq!(buf, &[0xc2]);
}
#[test]
fn test_encode_positive_fixint() {
let mut buf = vec![];
encode(&MsgValue::Int(42), &mut buf);
assert_eq!(buf[0], 42);
}
#[test]
fn test_encode_str() {
let mut buf = vec![];
encode(&MsgValue::Str("hi".to_string()), &mut buf);
assert_eq!(buf[0], 0xa0 | 2);
}
#[test]
fn test_is_nil() {
assert!(is_nil(&MsgValue::Nil));
assert!(!is_nil(&MsgValue::Bool(false)));
}
#[test]
fn test_array_len() {
let v = MsgValue::Array(vec![MsgValue::Nil, MsgValue::Bool(true)]);
assert_eq!(array_len(&v), 2);
}
#[test]
fn test_encoded_size_nil() {
assert_eq!(encoded_size(&MsgValue::Nil), 1);
}
#[test]
fn test_buffers_equal() {
assert!(buffers_equal(&[1, 2, 3], &[1, 2, 3]));
assert!(!buffers_equal(&[1], &[2]));
}
#[test]
fn test_encode_bin() {
let mut buf = vec![];
encode(&MsgValue::Bin(vec![0xDE, 0xAD]), &mut buf);
assert_eq!(buf[0], 0xc4);
assert_eq!(buf[1], 2);
}
}