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