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}