#[cfg(feature = "alloc")]
use alloc::string::String;
use core::fmt;
use crate::{
InvalidFieldErr, NotEnoughBytesErr, OtherErr, ReadCursor, UnexpectedMessageTypeErr, UnsupportedValueErr,
UnsupportedVersionErr,
};
pub type DecodeResult<T> = Result<T, DecodeError>;
pub type DecodeError = ironrdp_error::Error<DecodeErrorKind>;
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum DecodeErrorKind {
NotEnoughBytes {
received: usize,
expected: usize,
},
InvalidField {
field: &'static str,
reason: &'static str,
},
UnexpectedMessageType {
got: u8,
},
UnsupportedVersion {
got: u8,
},
#[cfg(feature = "alloc")]
UnsupportedValue {
name: &'static str,
value: String,
},
#[cfg(not(feature = "alloc"))]
UnsupportedValue {
name: &'static str,
},
Other {
description: &'static str,
},
}
#[cfg(feature = "std")]
impl core::error::Error for DecodeErrorKind {}
impl fmt::Display for DecodeErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotEnoughBytes { received, expected } => write!(
f,
"not enough bytes provided to decode: received {received} bytes, expected {expected} bytes"
),
Self::InvalidField { field, reason } => {
write!(f, "invalid `{field}`: {reason}")
}
Self::UnexpectedMessageType { got } => {
write!(f, "invalid message type ({got})")
}
Self::UnsupportedVersion { got } => {
write!(f, "unsupported version ({got})")
}
#[cfg(feature = "alloc")]
Self::UnsupportedValue { name, value } => {
write!(f, "unsupported {name} ({value})")
}
#[cfg(not(feature = "alloc"))]
Self::UnsupportedValue { name } => {
write!(f, "unsupported {name}")
}
Self::Other { description } => {
write!(f, "other ({description})")
}
}
}
}
impl NotEnoughBytesErr for DecodeError {
fn not_enough_bytes(context: &'static str, received: usize, expected: usize) -> Self {
Self::new(context, DecodeErrorKind::NotEnoughBytes { received, expected })
}
}
impl InvalidFieldErr for DecodeError {
fn invalid_field(context: &'static str, field: &'static str, reason: &'static str) -> Self {
Self::new(context, DecodeErrorKind::InvalidField { field, reason })
}
}
impl UnexpectedMessageTypeErr for DecodeError {
fn unexpected_message_type(context: &'static str, got: u8) -> Self {
Self::new(context, DecodeErrorKind::UnexpectedMessageType { got })
}
}
impl UnsupportedVersionErr for DecodeError {
fn unsupported_version(context: &'static str, got: u8) -> Self {
Self::new(context, DecodeErrorKind::UnsupportedVersion { got })
}
}
impl UnsupportedValueErr for DecodeError {
#[cfg(feature = "alloc")]
fn unsupported_value(context: &'static str, name: &'static str, value: String) -> Self {
Self::new(context, DecodeErrorKind::UnsupportedValue { name, value })
}
#[cfg(not(feature = "alloc"))]
fn unsupported_value(context: &'static str, name: &'static str) -> Self {
Self::new(context, DecodeErrorKind::UnsupportedValue { name })
}
}
impl OtherErr for DecodeError {
fn other(context: &'static str, description: &'static str) -> Self {
Self::new(context, DecodeErrorKind::Other { description })
}
}
pub trait Decode<'de>: Sized {
fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self>;
}
pub fn decode<'de, T>(src: &'de [u8]) -> DecodeResult<T>
where
T: Decode<'de>,
{
let mut cursor = ReadCursor::new(src);
T::decode(&mut cursor)
}
pub fn decode_cursor<'de, T>(src: &mut ReadCursor<'de>) -> DecodeResult<T>
where
T: Decode<'de>,
{
T::decode(src)
}
pub trait DecodeOwned: Sized {
fn decode_owned(src: &mut ReadCursor<'_>) -> DecodeResult<Self>;
}
pub fn decode_owned<T: DecodeOwned>(src: &[u8]) -> DecodeResult<T> {
let mut cursor = ReadCursor::new(src);
T::decode_owned(&mut cursor)
}
pub fn decode_owned_cursor<T: DecodeOwned>(src: &mut ReadCursor<'_>) -> DecodeResult<T> {
T::decode_owned(src)
}