Skip to main content

moqtap_codec/
kvp.rs

1use crate::varint::VarInt;
2use bytes::{Buf, BufMut};
3
4#[inline]
5#[allow(clippy::uninit_vec)]
6fn read_bytes_kvp(buf: &mut impl Buf, len: usize) -> Result<Vec<u8>, KvpError> {
7    if buf.remaining() < len {
8        return Err(KvpError::UnexpectedEnd);
9    }
10    let mut v = Vec::with_capacity(len);
11    // Safety: set_len(len) then overwrite all `len` bytes via copy_to_slice.
12    unsafe {
13        v.set_len(len);
14    }
15    buf.copy_to_slice(&mut v);
16    Ok(v)
17}
18
19/// Maximum value length for a Key-Value Pair: 2^16 - 1 bytes.
20pub const MAX_KVP_VALUE_LEN: usize = 65535;
21
22/// Value of a Key-Value Pair.
23/// Even key type -> varint value (no length field).
24/// Odd key type -> length-prefixed bytes.
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub enum KvpValue {
27    /// Varint value (used with even key types).
28    Varint(VarInt),
29    /// Length-prefixed byte string (used with odd key types).
30    Bytes(Vec<u8>),
31}
32
33/// A MoQT Key-Value Pair (used for parameters in control messages).
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct KeyValuePair {
36    /// Parameter key (even = varint value, odd = byte string value).
37    pub key: VarInt,
38    /// Parameter value.
39    pub value: KvpValue,
40}
41
42/// Errors produced when encoding or decoding key-value pairs.
43#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
44pub enum KvpError {
45    /// Odd key type was not followed by a length-prefixed value.
46    #[error("odd key type requires length-prefixed value")]
47    MissingLength,
48    /// Value length exceeds [`MAX_KVP_VALUE_LEN`].
49    #[error("value length {0} exceeds maximum ({MAX_KVP_VALUE_LEN})")]
50    ValueTooLong(usize),
51    /// Not enough bytes in the buffer to complete decoding.
52    #[error("insufficient bytes")]
53    UnexpectedEnd,
54    /// Variable-length integer encoding/decoding error.
55    #[error("varint error: {0}")]
56    VarInt(#[from] crate::varint::VarIntError),
57}
58
59impl KeyValuePair {
60    /// Encode a single key-value pair.
61    pub fn encode(&self, buf: &mut impl BufMut) {
62        self.key.encode(buf);
63        match &self.value {
64            KvpValue::Varint(v) => {
65                // Even key: write varint value directly
66                v.encode(buf);
67            }
68            KvpValue::Bytes(bytes) => {
69                // Odd key: write length-prefixed bytes
70                VarInt::from_usize(bytes.len()).encode(buf);
71                buf.put_slice(bytes);
72            }
73        }
74    }
75
76    /// Decode a single key-value pair.
77    pub fn decode(buf: &mut impl Buf) -> Result<Self, KvpError> {
78        let key = VarInt::decode(buf)?;
79        let key_val = key.into_inner();
80
81        if key_val % 2 == 0 {
82            // Even key: value is a varint
83            let value = VarInt::decode(buf)?;
84            Ok(KeyValuePair { key, value: KvpValue::Varint(value) })
85        } else {
86            // Odd key: value is length-prefixed bytes
87            let len = VarInt::decode(buf)?.into_inner() as usize;
88            if len > MAX_KVP_VALUE_LEN {
89                return Err(KvpError::ValueTooLong(len));
90            }
91            let bytes = read_bytes_kvp(buf, len)?;
92            Ok(KeyValuePair { key, value: KvpValue::Bytes(bytes) })
93        }
94    }
95
96    /// Encode a list of key-value pairs (count-prefixed).
97    pub fn encode_list(pairs: &[KeyValuePair], buf: &mut impl BufMut) {
98        VarInt::from_usize(pairs.len()).encode(buf);
99        for pair in pairs {
100            pair.encode(buf);
101        }
102    }
103
104    /// Decode a list of key-value pairs (count-prefixed).
105    pub fn decode_list(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, KvpError> {
106        let count = VarInt::decode(buf)?.into_inner() as usize;
107        let mut pairs = Vec::with_capacity(count);
108        for _ in 0..count {
109            pairs.push(KeyValuePair::decode(buf)?);
110        }
111        Ok(pairs)
112    }
113
114    /// Decode a single KVP using draft-07 format (all values are length-prefixed bytes).
115    pub fn decode_d07(buf: &mut impl Buf) -> Result<Self, KvpError> {
116        let key = VarInt::decode(buf)?;
117        let len = VarInt::decode(buf)?.into_inner() as usize;
118        if len > MAX_KVP_VALUE_LEN {
119            return Err(KvpError::ValueTooLong(len));
120        }
121        let bytes = read_bytes_kvp(buf, len)?;
122        Ok(KeyValuePair { key, value: KvpValue::Bytes(bytes) })
123    }
124
125    /// Encode a single KVP using draft-07 format (all values are length-prefixed).
126    pub fn encode_d07(&self, buf: &mut impl BufMut) {
127        self.key.encode(buf);
128        match &self.value {
129            KvpValue::Varint(v) => {
130                VarInt::from_usize(v.encoded_len()).encode(buf);
131                v.encode(buf);
132            }
133            KvpValue::Bytes(bytes) => {
134                VarInt::from_usize(bytes.len()).encode(buf);
135                buf.put_slice(bytes);
136            }
137        }
138    }
139
140    /// Decode a list of KVPs using draft-07 format.
141    pub fn decode_list_d07(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, KvpError> {
142        let count = VarInt::decode(buf)?.into_inner() as usize;
143        let mut pairs = Vec::with_capacity(count);
144        for _ in 0..count {
145            pairs.push(KeyValuePair::decode_d07(buf)?);
146        }
147        Ok(pairs)
148    }
149
150    /// Encode a list of KVPs using draft-07 format.
151    pub fn encode_list_d07(pairs: &[KeyValuePair], buf: &mut impl BufMut) {
152        VarInt::from_usize(pairs.len()).encode(buf);
153        for pair in pairs {
154            pair.encode_d07(buf);
155        }
156    }
157}