moq_lite/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)]
14pub enum DecodeError {
15	#[error("short buffer")]
16	Short,
17
18	#[error("long buffer")]
19	Long,
20
21	#[error("invalid string")]
22	InvalidString(#[from] FromUtf8Error),
23
24	#[error("invalid message: {0:?}")]
25	InvalidMessage(u64),
26
27	#[error("invalid subscribe location")]
28	InvalidSubscribeLocation,
29
30	#[error("invalid value")]
31	InvalidValue,
32
33	#[error("too many")]
34	TooMany,
35
36	#[error("bounds exceeded")]
37	BoundsExceeded,
38
39	#[error("expected end")]
40	ExpectedEnd,
41
42	#[error("expected data")]
43	ExpectedData,
44
45	#[error("duplicate")]
46	Duplicate,
47
48	#[error("missing")]
49	Missing,
50
51	#[error("unsupported")]
52	Unsupported,
53}
54
55impl<V> Decode<V> for bool {
56	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
57		match u8::decode(r, version)? {
58			0 => Ok(false),
59			1 => Ok(true),
60			_ => Err(DecodeError::InvalidValue),
61		}
62	}
63}
64
65impl<V> Decode<V> for u8 {
66	fn decode<R: bytes::Buf>(r: &mut R, _: V) -> Result<Self, DecodeError> {
67		match r.has_remaining() {
68			true => Ok(r.get_u8()),
69			false => Err(DecodeError::Short),
70		}
71	}
72}
73
74impl<V> Decode<V> for u16 {
75	fn decode<R: bytes::Buf>(r: &mut R, _: V) -> Result<Self, DecodeError> {
76		match r.remaining() >= 2 {
77			true => Ok(r.get_u16()),
78			false => Err(DecodeError::Short),
79		}
80	}
81}
82
83impl<V> Decode<V> for String {
84	/// Decode a string with a varint length prefix.
85	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
86		let v = Vec::<u8>::decode(r, version)?;
87		let str = String::from_utf8(v)?;
88
89		Ok(str)
90	}
91}
92
93impl<V> Decode<V> for Vec<u8> {
94	fn decode<B: bytes::Buf>(buf: &mut B, version: V) -> Result<Self, DecodeError> {
95		let size = usize::decode(buf, version)?;
96
97		if buf.remaining() < size {
98			return Err(DecodeError::Short);
99		}
100
101		let bytes = buf.copy_to_bytes(size);
102		Ok(bytes.to_vec())
103	}
104}
105
106impl<V> Decode<V> for i8 {
107	fn decode<R: bytes::Buf>(r: &mut R, _: V) -> Result<Self, DecodeError> {
108		if !r.has_remaining() {
109			return Err(DecodeError::Short);
110		}
111
112		// This is not the usual way of encoding negative numbers.
113		// i8 doesn't exist in the draft, but we use it instead of u8 for priority.
114		// A default of 0 is more ergonomic for the user than a default of 128.
115		Ok(((r.get_u8() as i16) - 128) as i8)
116	}
117}
118
119impl<V> Decode<V> for bytes::Bytes {
120	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
121		let len = usize::decode(r, version)?;
122		if r.remaining() < len {
123			return Err(DecodeError::Short);
124		}
125		let bytes = r.copy_to_bytes(len);
126		Ok(bytes)
127	}
128}
129
130// TODO Support borrowed strings.
131impl<V> Decode<V> for Cow<'_, str> {
132	fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
133		let s = String::decode(r, version)?;
134		Ok(Cow::Owned(s))
135	}
136}