use crate::varint::VarInt;
use bytes::{Buf, BufMut};
#[inline]
#[allow(clippy::uninit_vec)]
fn read_bytes_kvp(buf: &mut impl Buf, len: usize) -> Result<Vec<u8>, KvpError> {
if buf.remaining() < len {
return Err(KvpError::UnexpectedEnd);
}
let mut v = Vec::with_capacity(len);
unsafe {
v.set_len(len);
}
buf.copy_to_slice(&mut v);
Ok(v)
}
pub const MAX_KVP_VALUE_LEN: usize = 65535;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KvpValue {
Varint(VarInt),
Bytes(Vec<u8>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyValuePair {
pub key: VarInt,
pub value: KvpValue,
}
#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
pub enum KvpError {
#[error("odd key type requires length-prefixed value")]
MissingLength,
#[error("value length {0} exceeds maximum ({MAX_KVP_VALUE_LEN})")]
ValueTooLong(usize),
#[error("insufficient bytes")]
UnexpectedEnd,
#[error("varint error: {0}")]
VarInt(#[from] crate::varint::VarIntError),
}
impl KeyValuePair {
pub fn encode(&self, buf: &mut impl BufMut) {
self.key.encode(buf);
match &self.value {
KvpValue::Varint(v) => {
v.encode(buf);
}
KvpValue::Bytes(bytes) => {
VarInt::from_usize(bytes.len()).encode(buf);
buf.put_slice(bytes);
}
}
}
pub fn decode(buf: &mut impl Buf) -> Result<Self, KvpError> {
let key = VarInt::decode(buf)?;
let key_val = key.into_inner();
if key_val % 2 == 0 {
let value = VarInt::decode(buf)?;
Ok(KeyValuePair { key, value: KvpValue::Varint(value) })
} else {
let len = VarInt::decode(buf)?.into_inner() as usize;
if len > MAX_KVP_VALUE_LEN {
return Err(KvpError::ValueTooLong(len));
}
let bytes = read_bytes_kvp(buf, len)?;
Ok(KeyValuePair { key, value: KvpValue::Bytes(bytes) })
}
}
pub fn encode_list(pairs: &[KeyValuePair], buf: &mut impl BufMut) {
VarInt::from_usize(pairs.len()).encode(buf);
for pair in pairs {
pair.encode(buf);
}
}
pub fn decode_list(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, KvpError> {
let count = VarInt::decode(buf)?.into_inner() as usize;
let mut pairs = Vec::with_capacity(count);
for _ in 0..count {
pairs.push(KeyValuePair::decode(buf)?);
}
Ok(pairs)
}
pub fn decode_d07(buf: &mut impl Buf) -> Result<Self, KvpError> {
let key = VarInt::decode(buf)?;
let len = VarInt::decode(buf)?.into_inner() as usize;
if len > MAX_KVP_VALUE_LEN {
return Err(KvpError::ValueTooLong(len));
}
let bytes = read_bytes_kvp(buf, len)?;
Ok(KeyValuePair { key, value: KvpValue::Bytes(bytes) })
}
pub fn encode_d07(&self, buf: &mut impl BufMut) {
self.key.encode(buf);
match &self.value {
KvpValue::Varint(v) => {
VarInt::from_usize(v.encoded_len()).encode(buf);
v.encode(buf);
}
KvpValue::Bytes(bytes) => {
VarInt::from_usize(bytes.len()).encode(buf);
buf.put_slice(bytes);
}
}
}
pub fn decode_list_d07(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, KvpError> {
let count = VarInt::decode(buf)?.into_inner() as usize;
let mut pairs = Vec::with_capacity(count);
for _ in 0..count {
pairs.push(KeyValuePair::decode_d07(buf)?);
}
Ok(pairs)
}
pub fn encode_list_d07(pairs: &[KeyValuePair], buf: &mut impl BufMut) {
VarInt::from_usize(pairs.len()).encode(buf);
for pair in pairs {
pair.encode_d07(buf);
}
}
}