Skip to main content

moq_net/coding/
decode.rs

1use std::{borrow::Cow, string::FromUtf8Error};
2use thiserror::Error;
3
4/// Read the from the buffer using the given version.
5///
6/// If [DecodeError::Short] is returned, the caller should try again with more data.
7pub trait Decode<V>: Sized {
8	/// Decode the value from the given buffer.
9	fn decode<B: bytes::Buf>(buf: &mut B, version: V) -> Result<Self, DecodeError>;
10
11	/// The control metric class of this decoded value, or `None` for selectors and media headers.
12	fn control(&self, _version: V) -> Option<crate::stats::Control> {
13		None
14	}
15
16	/// Leading bytes of this value left out of its [`Self::control`] count: a type selector
17	/// the sender writes apart from the message, and so never counts.
18	fn uncounted(&self) -> usize {
19		0
20	}
21}
22
23/// A decode error.
24#[derive(Error, Debug, Clone)]
25#[non_exhaustive]
26pub enum DecodeError {
27	/// The buffer ran out mid-value. Retry once more bytes arrive.
28	#[error("short buffer")]
29	Short,
30
31	/// The value claims more bytes than the enclosing message allows.
32	#[error("long buffer")]
33	Long,
34
35	/// A string field was not valid UTF-8.
36	#[error("invalid string")]
37	InvalidString(#[from] FromUtf8Error),
38
39	/// The message type ID is unknown for the negotiated version.
40	#[error("invalid message: {0:?}")]
41	InvalidMessage(u64),
42
43	/// A SUBSCRIBE start/end location is malformed or out of order.
44	#[error("invalid subscribe location")]
45	InvalidSubscribeLocation,
46
47	/// A field held a value outside its permitted range.
48	#[error("invalid value")]
49	InvalidValue,
50
51	/// A repeated field exceeded the count this implementation accepts.
52	#[error("too many")]
53	TooMany,
54
55	/// An integer was too large for the QUIC varint range.
56	#[error("bounds exceeded")]
57	BoundsExceeded,
58
59	/// More data followed where the message was required to end.
60	#[error("expected end")]
61	ExpectedEnd,
62
63	/// A length-prefixed message exceeded the receiver's byte limit.
64	#[error("message too large: {size} bytes exceeds {max} byte limit")]
65	MessageTooLarge {
66		/// The byte length declared by the peer.
67		size: usize,
68		/// The largest message this receiver accepts.
69		max: usize,
70	},
71
72	/// The stream ended where a payload was required.
73	#[error("expected data")]
74	ExpectedData,
75
76	/// A parameter or field appeared more than once.
77	#[error("duplicate")]
78	Duplicate,
79
80	/// A required parameter or field was absent.
81	#[error("missing")]
82	Missing,
83
84	/// The value is well-formed but this implementation does not handle it.
85	#[error("unsupported")]
86	Unsupported,
87
88	/// Bytes remained after the value was fully decoded.
89	#[error("trailing bytes")]
90	TrailingBytes,
91
92	/// The field does not exist in the negotiated protocol version.
93	#[error("unsupported version")]
94	Version,
95}
96
97impl DecodeError {
98	/// A complete frame cannot be extended by reading more stream bytes.
99	pub(crate) fn complete(self) -> Self {
100		match self {
101			Self::Short => Self::InvalidValue,
102			other => other,
103		}
104	}
105}
106
107impl<V> Decode<V> for bool {
108	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
109		match u8::decode(r, version)? {
110			0 => Ok(false),
111			1 => Ok(true),
112			_ => Err(DecodeError::InvalidValue),
113		}
114	}
115}
116
117impl<V> Decode<V> for u8 {
118	fn decode<R: bytes::Buf>(r: &mut R, _: V) -> Result<Self, DecodeError> {
119		match r.has_remaining() {
120			true => Ok(r.get_u8()),
121			false => Err(DecodeError::Short),
122		}
123	}
124}
125
126impl<V> Decode<V> for u16 {
127	fn decode<R: bytes::Buf>(r: &mut R, _: V) -> Result<Self, DecodeError> {
128		match r.remaining() >= 2 {
129			true => Ok(r.get_u16()),
130			false => Err(DecodeError::Short),
131		}
132	}
133}
134
135impl<V: Copy> Decode<V> for String
136where
137	usize: Decode<V>,
138{
139	/// Decode a string with a varint length prefix.
140	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
141		let v = Vec::<u8>::decode(r, version)?;
142		let str = String::from_utf8(v)?;
143
144		Ok(str)
145	}
146}
147
148impl<V: Copy> Decode<V> for Vec<u8>
149where
150	usize: Decode<V>,
151{
152	fn decode<B: bytes::Buf>(buf: &mut B, version: V) -> Result<Self, DecodeError> {
153		let size = usize::decode(buf, version)?;
154
155		if buf.remaining() < size {
156			return Err(DecodeError::Short);
157		}
158
159		let bytes = buf.copy_to_bytes(size);
160		Ok(bytes.to_vec())
161	}
162}
163
164impl<V> Decode<V> for i8 {
165	fn decode<R: bytes::Buf>(r: &mut R, _: V) -> Result<Self, DecodeError> {
166		if !r.has_remaining() {
167			return Err(DecodeError::Short);
168		}
169
170		// This is not the usual way of encoding negative numbers.
171		// i8 doesn't exist in the draft, but we use it instead of u8 for priority.
172		// A default of 0 is more ergonomic for the user than a default of 128.
173		Ok(((r.get_u8() as i16) - 128) as i8)
174	}
175}
176
177impl<V: Copy> Decode<V> for bytes::Bytes
178where
179	usize: Decode<V>,
180{
181	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
182		let len = usize::decode(r, version)?;
183		if r.remaining() < len {
184			return Err(DecodeError::Short);
185		}
186		let bytes = r.copy_to_bytes(len);
187		Ok(bytes)
188	}
189}
190
191// TODO Support borrowed strings.
192impl<V: Copy> Decode<V> for Cow<'_, str>
193where
194	usize: Decode<V>,
195{
196	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
197		let s = String::decode(r, version)?;
198		Ok(Cow::Owned(s))
199	}
200}
201
202impl<V: Copy> Decode<V> for Option<u64>
203where
204	u64: Decode<V>,
205{
206	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
207		match u64::decode(r, version)? {
208			0 => Ok(None),
209			value => Ok(Some(value - 1)),
210		}
211	}
212}
213
214impl<V: Copy> Decode<V> for std::time::Duration
215where
216	u64: Decode<V>,
217{
218	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
219		let value = u64::decode(r, version)?;
220		Ok(Self::from_millis(value))
221	}
222}