ironrdp_core/decode.rs
1#[cfg(feature = "alloc")]
2use alloc::string::String;
3use core::fmt;
4
5use crate::{
6 InvalidFieldErr, NotEnoughBytesErr, OtherErr, ReadCursor, UnexpectedMessageTypeErr, UnsupportedValueErr,
7 UnsupportedVersionErr,
8};
9
10/// A result type for decoding operations, which can either succeed with a value of type `T`
11/// or fail with an [`DecodeError`].
12pub type DecodeResult<T> = Result<T, DecodeError>;
13
14/// An error type specifically for encoding operations, wrapping an [`DecodeErrorKind`].
15pub type DecodeError = ironrdp_error::Error<DecodeErrorKind>;
16
17/// Enum representing different kinds of decode errors.
18#[non_exhaustive]
19#[derive(Clone, Debug)]
20pub enum DecodeErrorKind {
21 /// Error when there are not enough bytes to decode.
22 NotEnoughBytes {
23 /// Number of bytes received.
24 received: usize,
25 /// Number of bytes expected.
26 expected: usize,
27 },
28 /// Error when a field is invalid.
29 InvalidField {
30 /// Name of the invalid field.
31 field: &'static str,
32 /// Reason for invalidity.
33 reason: &'static str,
34 },
35 /// Error when an unexpected message type is encountered.
36 UnexpectedMessageType {
37 /// The unexpected message type received.
38 got: u8,
39 },
40 /// Error when an unsupported version is encountered.
41 UnsupportedVersion {
42 /// The unsupported version received.
43 got: u8,
44 },
45 /// Error when an unsupported value is encountered (with allocation feature).
46 #[cfg(feature = "alloc")]
47 UnsupportedValue {
48 /// Name of the unsupported value.
49 name: &'static str,
50 /// The unsupported value.
51 value: String,
52 },
53 /// Error when an unsupported value is encountered (without allocation feature).
54 #[cfg(not(feature = "alloc"))]
55 UnsupportedValue {
56 /// Name of the unsupported value.
57 name: &'static str,
58 },
59 /// Generic error for other cases.
60 Other {
61 /// Description of the error.
62 description: &'static str,
63 },
64}
65
66#[cfg(feature = "std")]
67impl std::error::Error for DecodeErrorKind {}
68
69impl fmt::Display for DecodeErrorKind {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 match self {
72 Self::NotEnoughBytes { received, expected } => write!(
73 f,
74 "not enough bytes provided to decode: received {received} bytes, expected {expected} bytes"
75 ),
76 Self::InvalidField { field, reason } => {
77 write!(f, "invalid `{field}`: {reason}")
78 }
79 Self::UnexpectedMessageType { got } => {
80 write!(f, "invalid message type ({got})")
81 }
82 Self::UnsupportedVersion { got } => {
83 write!(f, "unsupported version ({got})")
84 }
85 #[cfg(feature = "alloc")]
86 Self::UnsupportedValue { name, value } => {
87 write!(f, "unsupported {name} ({value})")
88 }
89 #[cfg(not(feature = "alloc"))]
90 Self::UnsupportedValue { name } => {
91 write!(f, "unsupported {name}")
92 }
93 Self::Other { description } => {
94 write!(f, "other ({description})")
95 }
96 }
97 }
98}
99
100impl NotEnoughBytesErr for DecodeError {
101 fn not_enough_bytes(context: &'static str, received: usize, expected: usize) -> Self {
102 Self::new(context, DecodeErrorKind::NotEnoughBytes { received, expected })
103 }
104}
105
106impl InvalidFieldErr for DecodeError {
107 fn invalid_field(context: &'static str, field: &'static str, reason: &'static str) -> Self {
108 Self::new(context, DecodeErrorKind::InvalidField { field, reason })
109 }
110}
111
112impl UnexpectedMessageTypeErr for DecodeError {
113 fn unexpected_message_type(context: &'static str, got: u8) -> Self {
114 Self::new(context, DecodeErrorKind::UnexpectedMessageType { got })
115 }
116}
117
118impl UnsupportedVersionErr for DecodeError {
119 fn unsupported_version(context: &'static str, got: u8) -> Self {
120 Self::new(context, DecodeErrorKind::UnsupportedVersion { got })
121 }
122}
123
124impl UnsupportedValueErr for DecodeError {
125 #[cfg(feature = "alloc")]
126 fn unsupported_value(context: &'static str, name: &'static str, value: String) -> Self {
127 Self::new(context, DecodeErrorKind::UnsupportedValue { name, value })
128 }
129 #[cfg(not(feature = "alloc"))]
130 fn unsupported_value(context: &'static str, name: &'static str) -> Self {
131 Self::new(context, DecodeErrorKind::UnsupportedValue { name })
132 }
133}
134
135impl OtherErr for DecodeError {
136 fn other(context: &'static str, description: &'static str) -> Self {
137 Self::new(context, DecodeErrorKind::Other { description })
138 }
139}
140
141/// Trait for types that can be decoded from a byte stream.
142///
143/// This trait is implemented by types that can be deserialized from a sequence of bytes.
144pub trait Decode<'de>: Sized {
145 /// Decodes an instance of `Self` from the given byte stream.
146 ///
147 /// # Arguments
148 ///
149 /// * `src` - A mutable reference to a `ReadCursor` containing the bytes to decode.
150 ///
151 /// # Returns
152 ///
153 /// Returns a `DecodeResult<Self>`, which is either the successfully decoded instance
154 /// or a `DecodeError` if decoding fails.
155 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self>;
156}
157
158/// Decodes a value of type `T` from a byte slice.
159///
160/// This function creates a `ReadCursor` from the input byte slice and uses it to decode
161/// a value of type `T` that implements the `Decode` trait.
162///
163/// # Arguments
164///
165/// * `src` - A byte slice containing the data to be decoded.
166///
167/// # Returns
168///
169/// Returns a `DecodeResult<T>`, which is either the successfully decoded value
170/// or a `DecodeError` if decoding fails.
171pub fn decode<'de, T>(src: &'de [u8]) -> DecodeResult<T>
172where
173 T: Decode<'de>,
174{
175 let mut cursor = ReadCursor::new(src);
176 T::decode(&mut cursor)
177}
178
179/// Decodes a value of type `T` from a `ReadCursor`.
180///
181/// This function uses the provided `ReadCursor` to decode a value of type `T`
182/// that implements the `Decode` trait.
183///
184/// # Arguments
185///
186/// * `src` - A mutable reference to a `ReadCursor` containing the bytes to be decoded.
187///
188/// # Returns
189///
190/// Returns a `DecodeResult<T>`, which is either the successfully decoded value
191/// or a `DecodeError` if decoding fails.
192pub fn decode_cursor<'de, T>(src: &mut ReadCursor<'de>) -> DecodeResult<T>
193where
194 T: Decode<'de>,
195{
196 T::decode(src)
197}
198
199/// Similar to `Decode` but unconditionally returns an owned type.
200pub trait DecodeOwned: Sized {
201 /// Decodes an instance of `Self` from the given byte stream.
202 ///
203 /// # Arguments
204 ///
205 /// * `src` - A mutable reference to a `ReadCursor` containing the bytes to decode.
206 ///
207 /// # Returns
208 ///
209 /// Returns a `DecodeResult<Self>`, which is either the successfully decoded instance
210 /// or a `DecodeError` if decoding fails.
211 fn decode_owned(src: &mut ReadCursor<'_>) -> DecodeResult<Self>;
212}
213
214/// Decodes an owned value of type `T` from a byte slice.
215///
216/// This function creates a `ReadCursor` from the input byte slice and uses it to decode
217/// an owned value of type `T` that implements the `DecodeOwned` trait.
218///
219/// # Arguments
220///
221/// * `src` - A byte slice containing the data to be decoded.
222///
223/// # Returns
224///
225/// Returns a `DecodeResult<T>`, which is either the successfully decoded owned value
226/// or a `DecodeError` if decoding fails.
227pub fn decode_owned<T: DecodeOwned>(src: &[u8]) -> DecodeResult<T> {
228 let mut cursor = ReadCursor::new(src);
229 T::decode_owned(&mut cursor)
230}
231
232/// Decodes an owned value of type `T` from a `ReadCursor`.
233///
234/// This function uses the provided `ReadCursor` to decode an owned value of type `T`
235/// that implements the `DecodeOwned` trait.
236///
237/// # Arguments
238///
239/// * `src` - A mutable reference to a `ReadCursor` containing the bytes to be decoded.
240///
241/// # Returns
242///
243/// Returns a `DecodeResult<T>`, which is either the successfully decoded owned value
244/// or a `DecodeError` if decoding fails.
245pub fn decode_owned_cursor<T: DecodeOwned>(src: &mut ReadCursor<'_>) -> DecodeResult<T> {
246 T::decode_owned(src)
247}