mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-08-04 15:18:17 +00:00
refactor(core): move Encode/Decode to core
ironrdp-pdu contains lots of code that we don’t actually need in other crates such as the virtual channels. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
ab5760d47b
commit
402ffd56c9
197 changed files with 575 additions and 457 deletions
|
@ -3,13 +3,15 @@ use alloc::string::String;
|
|||
use core::fmt;
|
||||
|
||||
use crate::{
|
||||
InvalidFieldErr, NotEnoughBytesErr, OtherErr, UnexpectedMessageTypeErr, UnsupportedValueErr, UnsupportedVersionErr,
|
||||
InvalidFieldErr, NotEnoughBytesErr, OtherErr, ReadCursor, UnexpectedMessageTypeErr, UnsupportedValueErr,
|
||||
UnsupportedVersionErr,
|
||||
};
|
||||
|
||||
/// Result type for decode operations, wrapping a value or a DecodeError.
|
||||
/// A result type for decoding operations, which can either succeed with a value of type `T`
|
||||
/// or fail with an [`DecodeError`].
|
||||
pub type DecodeResult<T> = Result<T, DecodeError>;
|
||||
|
||||
/// Custom error type for decode operations.
|
||||
/// An error type specifically for encoding operations, wrapping an [`DecodeErrorKind`].
|
||||
pub type DecodeError = ironrdp_error::Error<DecodeErrorKind>;
|
||||
|
||||
/// Enum representing different kinds of decode errors.
|
||||
|
@ -135,3 +137,111 @@ impl OtherErr for DecodeError {
|
|||
Self::new(context, DecodeErrorKind::Other { description })
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types that can be decoded from a byte stream.
|
||||
///
|
||||
/// This trait is implemented by types that can be deserialized from a sequence of bytes.
|
||||
pub trait Decode<'de>: Sized {
|
||||
/// Decodes an instance of `Self` from the given byte stream.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `src` - A mutable reference to a `ReadCursor` containing the bytes to decode.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a `DecodeResult<Self>`, which is either the successfully decoded instance
|
||||
/// or a `DecodeError` if decoding fails.
|
||||
fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self>;
|
||||
}
|
||||
|
||||
/// Decodes a value of type `T` from a byte slice.
|
||||
///
|
||||
/// This function creates a `ReadCursor` from the input byte slice and uses it to decode
|
||||
/// a value of type `T` that implements the `Decode` trait.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `src` - A byte slice containing the data to be decoded.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a `DecodeResult<T>`, which is either the successfully decoded value
|
||||
/// or a `DecodeError` if decoding fails.
|
||||
pub fn decode<'de, T>(src: &'de [u8]) -> DecodeResult<T>
|
||||
where
|
||||
T: Decode<'de>,
|
||||
{
|
||||
let mut cursor = ReadCursor::new(src);
|
||||
T::decode(&mut cursor)
|
||||
}
|
||||
|
||||
/// Decodes a value of type `T` from a `ReadCursor`.
|
||||
///
|
||||
/// This function uses the provided `ReadCursor` to decode a value of type `T`
|
||||
/// that implements the `Decode` trait.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `src` - A mutable reference to a `ReadCursor` containing the bytes to be decoded.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a `DecodeResult<T>`, which is either the successfully decoded value
|
||||
/// or a `DecodeError` if decoding fails.
|
||||
pub fn decode_cursor<'de, T>(src: &mut ReadCursor<'de>) -> DecodeResult<T>
|
||||
where
|
||||
T: Decode<'de>,
|
||||
{
|
||||
T::decode(src)
|
||||
}
|
||||
|
||||
/// Similar to `Decode` but unconditionally returns an owned type.
|
||||
pub trait DecodeOwned: Sized {
|
||||
/// Decodes an instance of `Self` from the given byte stream.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `src` - A mutable reference to a `ReadCursor` containing the bytes to decode.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a `DecodeResult<Self>`, which is either the successfully decoded instance
|
||||
/// or a `DecodeError` if decoding fails.
|
||||
fn decode_owned(src: &mut ReadCursor<'_>) -> DecodeResult<Self>;
|
||||
}
|
||||
|
||||
/// Decodes an owned value of type `T` from a byte slice.
|
||||
///
|
||||
/// This function creates a `ReadCursor` from the input byte slice and uses it to decode
|
||||
/// an owned value of type `T` that implements the `DecodeOwned` trait.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `src` - A byte slice containing the data to be decoded.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a `DecodeResult<T>`, which is either the successfully decoded owned value
|
||||
/// or a `DecodeError` if decoding fails.
|
||||
pub fn decode_owned<T: DecodeOwned>(src: &[u8]) -> DecodeResult<T> {
|
||||
let mut cursor = ReadCursor::new(src);
|
||||
T::decode_owned(&mut cursor)
|
||||
}
|
||||
|
||||
/// Decodes an owned value of type `T` from a `ReadCursor`.
|
||||
///
|
||||
/// This function uses the provided `ReadCursor` to decode an owned value of type `T`
|
||||
/// that implements the `DecodeOwned` trait.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `src` - A mutable reference to a `ReadCursor` containing the bytes to be decoded.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a `DecodeResult<T>`, which is either the successfully decoded owned value
|
||||
/// or a `DecodeError` if decoding fails.
|
||||
pub fn decode_owned_cursor<T: DecodeOwned>(src: &mut ReadCursor<'_>) -> DecodeResult<T> {
|
||||
T::decode_owned(src)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
#[cfg(feature = "alloc")]
|
||||
use crate::WriteBuf;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::String;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::{vec, vec::Vec};
|
||||
use core::fmt;
|
||||
|
||||
use crate::{
|
||||
InvalidFieldErr, NotEnoughBytesErr, OtherErr, UnexpectedMessageTypeErr, UnsupportedValueErr, UnsupportedVersionErr,
|
||||
WriteCursor,
|
||||
};
|
||||
|
||||
/// A result type for encoding operations, which can either succeed with a value of type `T`
|
||||
/// or fail with an `EncodeError`.
|
||||
/// or fail with an [`EncodeError`].
|
||||
pub type EncodeResult<T> = Result<T, EncodeError>;
|
||||
|
||||
/// An error type specifically for encoding operations, wrapping an `EncodeErrorKind`.
|
||||
/// An error type specifically for encoding operations, wrapping an [`EncodeErrorKind`].
|
||||
pub type EncodeError = ironrdp_error::Error<EncodeErrorKind>;
|
||||
|
||||
/// Represents the different kinds of errors that can occur during encoding operations.
|
||||
|
@ -136,3 +141,106 @@ impl OtherErr for EncodeError {
|
|||
Self::new(context, EncodeErrorKind::Other { description })
|
||||
}
|
||||
}
|
||||
|
||||
/// PDU that can be encoded into its binary form.
|
||||
///
|
||||
/// The resulting binary payload is a fully encoded PDU that may be sent to the peer.
|
||||
///
|
||||
/// This trait is object-safe and may be used in a dynamic context.
|
||||
pub trait Encode {
|
||||
/// Encodes this PDU in-place using the provided `WriteCursor`.
|
||||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()>;
|
||||
|
||||
/// Returns the associated PDU name associated.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Computes the size in bytes for this PDU.
|
||||
fn size(&self) -> usize;
|
||||
}
|
||||
|
||||
crate::assert_obj_safe!(Encode);
|
||||
|
||||
/// Encodes the given PDU in-place into the provided buffer and returns the number of bytes written.
|
||||
pub fn encode<T>(pdu: &T, dst: &mut [u8]) -> EncodeResult<usize>
|
||||
where
|
||||
T: Encode + ?Sized,
|
||||
{
|
||||
let mut cursor = WriteCursor::new(dst);
|
||||
encode_cursor(pdu, &mut cursor)?;
|
||||
Ok(cursor.pos())
|
||||
}
|
||||
|
||||
/// Encodes the given PDU in-place using the provided `WriteCursor`.
|
||||
pub fn encode_cursor<T>(pdu: &T, dst: &mut WriteCursor<'_>) -> EncodeResult<()>
|
||||
where
|
||||
T: Encode + ?Sized,
|
||||
{
|
||||
pdu.encode(dst)
|
||||
}
|
||||
|
||||
/// Same as `encode` but resizes the buffer when it is too small to fit the PDU.
|
||||
#[cfg(feature = "alloc")]
|
||||
pub fn encode_buf<T>(pdu: &T, buf: &mut WriteBuf) -> EncodeResult<usize>
|
||||
where
|
||||
T: Encode + ?Sized,
|
||||
{
|
||||
let pdu_size = pdu.size();
|
||||
let dst = buf.unfilled_to(pdu_size);
|
||||
let written = encode(pdu, dst)?;
|
||||
debug_assert_eq!(written, pdu_size);
|
||||
buf.advance(written);
|
||||
Ok(written)
|
||||
}
|
||||
|
||||
/// Same as `encode` but allocates and returns a new buffer each time.
|
||||
///
|
||||
/// This is a convenience function, but it’s not very resource efficient.
|
||||
#[cfg(any(feature = "alloc", test))]
|
||||
pub fn encode_vec<T>(pdu: &T) -> EncodeResult<Vec<u8>>
|
||||
where
|
||||
T: Encode + ?Sized,
|
||||
{
|
||||
let pdu_size = pdu.size();
|
||||
let mut buf = vec![0; pdu_size];
|
||||
let written = encode(pdu, buf.as_mut_slice())?;
|
||||
debug_assert_eq!(written, pdu_size);
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Gets the name of this PDU.
|
||||
pub fn name<T: Encode>(pdu: &T) -> &'static str {
|
||||
pdu.name()
|
||||
}
|
||||
|
||||
/// Computes the size in bytes for this PDU.
|
||||
pub fn size<T: Encode>(pdu: &T) -> usize {
|
||||
pdu.size()
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use legacy::*;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
mod legacy {
|
||||
use super::{Encode, EncodeResult};
|
||||
use crate::WriteCursor;
|
||||
|
||||
impl Encode for alloc::vec::Vec<u8> {
|
||||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: self.len());
|
||||
|
||||
dst.write_slice(self);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the associated PDU name associated.
|
||||
fn name(&self) -> &'static str {
|
||||
"legacy-pdu-encode"
|
||||
}
|
||||
|
||||
/// Computes the size in bytes for this PDU.
|
||||
fn size(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue