use bytes::BytesMut;
use crate::decode::DecodeError;
pub trait Decode: Sized {
fn decode(src: &mut BytesMut) -> Result<(Self, usize), DecodeError>;
}
pub trait DecodeWithLength: Sized {
fn decode(src: &mut BytesMut, length: usize) -> Result<(Self, usize), DecodeError>;
}
impl<T: Decode> DecodeWithLength for T {
fn decode(src: &mut BytesMut, _length: usize) -> Result<(Self, usize), DecodeError> {
Decode::decode(src)
}
}
pub trait DecodeWithKey: Sized {
type Key;
fn decode(
key: Self::Key,
src: &mut BytesMut,
length: usize,
) -> Result<(Self, usize), DecodeError>;
}
pub trait DecodeWithKeyOptional: Sized {
type Key;
fn decode(
key: Self::Key,
src: &mut BytesMut,
length: usize,
) -> Result<Option<(Self, usize)>, DecodeError>;
}
#[doc(hidden)]
pub trait DecodeExt: Decode {
fn decode_move(src: &mut BytesMut, size: usize) -> Result<(Self, usize), DecodeError> {
Self::decode(src).map(|(this, size_)| (this, size + size_))
}
fn counted(
src: &mut BytesMut,
count: usize,
) -> Result<(alloc::vec::Vec<Self>, usize), DecodeError> {
(0..count).try_fold(
(alloc::vec::Vec::with_capacity(count), 0),
|(mut vec, size), _| {
Self::decode(src).map(|(item, size_)| {
vec.push(item);
(vec, size + size_)
})
},
)
}
fn counted_move(
src: &mut BytesMut,
count: usize,
size: usize,
) -> Result<(alloc::vec::Vec<Self>, usize), DecodeError> {
Self::counted(src, count).map(|(vec, size_)| (vec, size + size_))
}
fn length_checked_decode(
src: &mut BytesMut,
length: usize,
) -> Result<Option<(Self, usize)>, DecodeError> {
(length > 0)
.then_some(())
.map(|_| Self::decode(src))
.transpose()
}
fn length_checked_decode_move(
src: &mut BytesMut,
length: usize,
size: usize,
) -> Result<Option<(Self, usize)>, DecodeError> {
Self::length_checked_decode(src, length)
.map(|decoded| decoded.map(|(this, size_)| (this, size + size_)))
}
}
impl<T: Decode> DecodeExt for T {}
#[doc(hidden)]
pub trait DecodeWithLengthExt: DecodeWithLength {
fn decode_move(
src: &mut BytesMut,
length: usize,
size: usize,
) -> Result<(Self, usize), DecodeError> {
Self::decode(src, length).map(|(this, size_)| (this, size + size_))
}
}
impl<T: DecodeWithLength> DecodeWithLengthExt for T {}
#[doc(hidden)]
pub trait DecodeWithKeyExt: DecodeWithKey {
fn optional_length_checked_decode(
key: Self::Key,
src: &mut BytesMut,
length: usize,
) -> Result<Option<(Self, usize)>, DecodeError> {
(length > 0)
.then_some(())
.map(|_| Self::decode(key, src, length))
.transpose()
}
fn optional_length_checked_decode_move(
key: Self::Key,
src: &mut BytesMut,
length: usize,
size: usize,
) -> Result<Option<(Self, usize)>, DecodeError> {
Self::optional_length_checked_decode(key, src, length)
.map(|decoded| decoded.map(|(this, size_)| (this, size + size_)))
}
}
impl<T: DecodeWithKey> DecodeWithKeyExt for T {}
#[doc(hidden)]
pub trait DecodeWithKeyOptionalExt: DecodeWithKeyOptional {
fn decode_move(
key: Self::Key,
src: &mut BytesMut,
length: usize,
size: usize,
) -> Result<Option<(Self, usize)>, DecodeError> {
Self::decode(key, src, length)
.map(|decoded| decoded.map(|(this, size_)| (this, size + size_)))
}
}
impl<T: DecodeWithKeyOptional> DecodeWithKeyOptionalExt for T {}
impl<T: Decode> DecodeWithLength for alloc::vec::Vec<T> {
fn decode(src: &mut BytesMut, length: usize) -> Result<(Self, usize), DecodeError> {
if length == 0 {
return Ok((alloc::vec::Vec::new(), 0));
}
if length > src.len() {
return Err(DecodeError::unexpected_eof());
}
let mut src = src.split_to(length);
let mut size = 0;
let mut vec = alloc::vec::Vec::new();
while size < length {
let (item, size_) = T::decode(&mut src)?;
size += size_;
vec.push(item);
}
Ok((vec, size))
}
}
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use crate::{
decode::{COctetStringDecodeError, DecodeErrorKind},
types::owned::{COctetString, EmptyOrFullCOctetString},
};
use super::*;
#[test]
fn counted() {
let mut buf = BytesMut::from(&[0, 1, 2][..]);
let (values, size) = u8::counted(&mut buf, 0).unwrap();
assert_eq!(size, 0);
assert_eq!(values.len(), 0);
assert_eq!(&buf[..], &[0, 1, 2]);
assert_eq!(values, Vec::<u8>::new());
let mut buf = BytesMut::from(&[0, 1, 2][..]);
let error = u8::counted(&mut buf, 5).unwrap_err();
assert!(matches!(error.kind(), DecodeErrorKind::UnexpectedEof));
let mut buf = BytesMut::from(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]);
let (values, size) = u8::counted(&mut buf, 10).unwrap();
assert_eq!(size, 10);
assert_eq!(values.len(), 10);
assert!(buf.is_empty());
assert_eq!(values, alloc::vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let mut buf =
BytesMut::from(&[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9][..]);
let (values, size) = u16::counted(&mut buf, 10).unwrap();
assert_eq!(size, 20);
assert_eq!(values.len(), 10);
assert!(buf.is_empty());
assert_eq!(values, alloc::vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let mut buf = BytesMut::from(
&[
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6,
0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9,
][..],
);
let error = u32::counted(&mut buf, 12).unwrap_err();
assert!(matches!(error.kind(), DecodeErrorKind::UnexpectedEof));
let mut buf = BytesMut::from(&b"Hello\0World\0"[..]);
let (values, size) = COctetString::<1, 6>::counted_move(&mut buf, 2, 0).unwrap();
assert_eq!(size, 12);
assert!(&buf[..].is_empty());
assert_eq!(
values,
alloc::vec![
COctetString::<1, 6>::from_static_slice(b"Hello\0").unwrap(),
COctetString::<1, 6>::from_static_slice(b"World\0").unwrap(),
]
);
let mut buf = BytesMut::from(&b"Hello\0World\0"[..]);
let (values, size) = EmptyOrFullCOctetString::<6>::counted_move(&mut buf, 2, 0).unwrap();
assert_eq!(size, 12);
assert!(&buf[..].is_empty());
assert_eq!(
values,
alloc::vec![
EmptyOrFullCOctetString::<6>::from_static_slice(b"Hello\0").unwrap(),
EmptyOrFullCOctetString::<6>::from_static_slice(b"World\0").unwrap(),
]
);
let mut buf = BytesMut::from(&b"Hello\0World\0Hi"[..]);
let error = COctetString::<1, 6>::counted_move(&mut buf, 3, 0).unwrap_err();
assert!(matches!(
error.kind(),
DecodeErrorKind::COctetStringDecodeError(COctetStringDecodeError::NotNullTerminated)
));
let mut buf = BytesMut::from(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]);
let (values, size) = u8::counted_move(&mut buf, 5, 0).unwrap();
assert_eq!(size, 5);
assert_eq!(&buf[..], &[5, 6, 7, 8, 9]);
assert_eq!(values, alloc::vec![0, 1, 2, 3, 4]);
let mut buf =
BytesMut::from(&[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9][..]);
let (values, size) = u16::counted_move(&mut buf, 5, 0).unwrap();
assert_eq!(size, 10);
assert_eq!(&buf[..], &[0, 5, 0, 6, 0, 7, 0, 8, 0, 9]);
assert_eq!(values, alloc::vec![0, 1, 2, 3, 4]);
}
#[test]
fn decode_with_length_vec() {
let mut buf = BytesMut::from(&[0, 1, 2][..]);
let (values, size) = Vec::<u8>::decode(&mut buf, 0).unwrap();
assert_eq!(size, 0);
assert_eq!(&buf[..], &[0, 1, 2]);
assert_eq!(values, Vec::<u8>::new());
let mut buf = BytesMut::from(&[0, 1, 2][..]);
let error = Vec::<u8>::decode(&mut buf, 5).unwrap_err();
assert!(matches!(error.kind(), DecodeErrorKind::UnexpectedEof));
let mut buf = BytesMut::from(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]);
let (values, size) = Vec::<u8>::decode(&mut buf, 10).unwrap();
assert_eq!(size, 10);
assert!(buf.is_empty());
assert_eq!(values, alloc::vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let mut buf =
BytesMut::from(&[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9][..]);
let (values, size) = Vec::<u16>::decode(&mut buf, 20).unwrap();
assert_eq!(size, 20);
assert!(buf.is_empty());
assert_eq!(values, alloc::vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let mut buf = BytesMut::from(
&[
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6,
0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9,
][..],
);
let error = Vec::<u32>::decode(&mut buf, 50).unwrap_err();
assert!(matches!(error.kind(), DecodeErrorKind::UnexpectedEof));
let mut buf = BytesMut::from(&b"Hello\0World\0"[..]);
let (values, size) = Vec::<COctetString<1, 6>>::decode(&mut buf, 12).unwrap();
assert_eq!(size, 12);
assert!(buf.is_empty());
assert_eq!(
values,
alloc::vec![
COctetString::<1, 6>::from_static_slice(b"Hello\0").unwrap(),
COctetString::<1, 6>::from_static_slice(b"World\0").unwrap(),
]
);
let mut buf = BytesMut::from(&b"Hello\0World\0"[..]);
let (values, size) = Vec::<EmptyOrFullCOctetString<6>>::decode(&mut buf, 12).unwrap();
assert_eq!(size, 12);
assert!(buf.is_empty());
assert_eq!(
values,
alloc::vec![
EmptyOrFullCOctetString::<6>::from_static_slice(b"Hello\0").unwrap(),
EmptyOrFullCOctetString::<6>::from_static_slice(b"World\0").unwrap(),
]
);
let mut buf = BytesMut::from(&b"Hello\0World\0Hi"[..]);
let error = Vec::<COctetString<1, 6>>::decode(&mut buf, 11).unwrap_err();
assert!(matches!(
error.kind(),
DecodeErrorKind::COctetStringDecodeError(COctetStringDecodeError::NotNullTerminated)
));
let mut buf = BytesMut::from(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]);
let (values, size) = Vec::<u8>::decode(&mut buf, 5).unwrap();
assert_eq!(size, 5);
assert_eq!(&buf[..], &[5, 6, 7, 8, 9]);
assert_eq!(values, alloc::vec![0, 1, 2, 3, 4]);
let mut buf =
BytesMut::from(&[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9][..]);
let (values, size) = Vec::<u16>::decode(&mut buf, 10).unwrap();
assert_eq!(size, 10);
assert_eq!(&buf[..], &[0, 5, 0, 6, 0, 7, 0, 8, 0, 9]);
assert_eq!(values, alloc::vec![0, 1, 2, 3, 4]);
}
}