use super::{ExtensionRef, FixedExtension, read_ext_header};
use crate::Format;
use crate::decode::{DecodeBorrowed, Error as DecodeError};
use crate::io::IoRead;
impl<'de> DecodeBorrowed<'de> for ExtensionRef<'de> {
type Value = ExtensionRef<'de>;
fn decode_borrowed_with_format<R>(
format: Format,
reader: &mut R,
) -> core::result::Result<Self::Value, DecodeError<R::Error>>
where
R: IoRead<'de>,
{
let (len, ext_type) = read_ext_header(format, reader)?;
let data_ref = reader.read_slice(len).map_err(DecodeError::Io)?;
let data = match data_ref {
crate::io::Reference::Borrowed(b) => b,
crate::io::Reference::Copied(_) => return Err(DecodeError::InvalidData),
};
Ok(ExtensionRef {
r#type: ext_type,
data,
})
}
}
impl<'de, const N: usize> DecodeBorrowed<'de> for FixedExtension<N> {
type Value = FixedExtension<N>;
fn decode_borrowed_with_format<R>(
format: Format,
reader: &mut R,
) -> core::result::Result<Self::Value, DecodeError<R::Error>>
where
R: IoRead<'de>,
{
let (len, ext_type) = read_ext_header(format, reader)?;
if len > N {
return Err(DecodeError::InvalidData);
}
let payload = reader.read_slice(len).map_err(DecodeError::Io)?;
let bytes = payload.as_bytes();
if bytes.len() != len {
return Err(DecodeError::UnexpectedEof);
}
let mut data = [0u8; N];
data[..len].copy_from_slice(bytes);
Ok(FixedExtension {
r#type: ext_type,
len,
data,
})
}
}
#[cfg(feature = "alloc")]
impl<'de> DecodeBorrowed<'de> for super::owned::ExtensionOwned {
type Value = super::owned::ExtensionOwned;
fn decode_borrowed_with_format<R>(
format: Format,
reader: &mut R,
) -> core::result::Result<Self::Value, DecodeError<R::Error>>
where
R: crate::io::IoRead<'de>,
{
let (len, ext_type) = read_ext_header(format, reader)?;
let payload = reader.read_slice(len).map_err(DecodeError::Io)?;
let data = payload.as_bytes().to_vec();
Ok(super::owned::ExtensionOwned {
r#type: ext_type,
data,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::decode::Decode;
use crate::encode::Encode;
#[rstest::rstest]
#[case(crate::Format::FixExt1.as_byte(), 5_i8, [0x12])]
#[case(crate::Format::FixExt2.as_byte(), -1_i8, [0x34, 0x56])]
#[case(crate::Format::FixExt4.as_byte(), 42_i8, [0xde, 0xad, 0xbe, 0xef])]
#[case(crate::Format::FixExt8.as_byte(), -7_i8, [0xAA; 8])]
#[case(crate::Format::FixExt16.as_byte(), 7_i8, [0x55; 16])]
fn decode_ext_fixed<E: AsRef<[u8]>>(#[case] marker: u8, #[case] ty: i8, #[case] data: E) {
let buf = core::iter::once(marker)
.chain(core::iter::once(ty as u8))
.chain(data.as_ref().iter().cloned())
.collect::<Vec<u8>>();
let mut r = crate::io::SliceReader::new(&buf);
let ext = ExtensionRef::decode(&mut r).unwrap();
assert_eq!(ext.r#type, ty);
assert_eq!(ext.data, data.as_ref());
assert!(r.rest().is_empty());
}
#[rstest::rstest]
#[case(crate::Format::Ext8, 42_i8, 5u8.to_be_bytes(), [0x11;5])] #[case(crate::Format::Ext16, -7_i8, 300u16.to_be_bytes(), [0xAA;300])] #[case(crate::Format::Ext32, 7_i8, 70000u32.to_be_bytes(), [0x55;70000])] fn decode_ext_sized<S: AsRef<[u8]>, D: AsRef<[u8]>>(
#[case] format: crate::Format,
#[case] ty: i8,
#[case] size: S,
#[case] data: D,
) {
let buf = format
.as_slice()
.iter()
.chain(size.as_ref())
.chain(ty.to_be_bytes().iter())
.chain(data.as_ref())
.cloned()
.collect::<Vec<_>>();
let mut r = crate::io::SliceReader::new(&buf);
let ext = ExtensionRef::decode(&mut r).unwrap();
assert_eq!(ext.r#type, ty);
assert_eq!(ext.data, data.as_ref());
assert!(r.rest().is_empty());
}
#[rstest::rstest]
fn fixed_extension_roundtrip() {
let data = [1u8, 2, 3, 4];
let ext = FixedExtension::<8>::new(5, &data).unwrap();
let mut buf = vec![];
ext.encode(&mut buf).unwrap();
let mut r = crate::io::SliceReader::new(&buf);
let decoded = FixedExtension::<8>::decode(&mut r).unwrap();
assert_eq!(decoded.r#type, 5);
assert_eq!(decoded.as_slice(), &data);
assert!(r.rest().is_empty());
}
#[cfg(feature = "std")]
#[rstest::rstest]
fn fixed_extension_decode_with_std_reader_copied() {
let mut buf = vec![];
buf.extend_from_slice(&[crate::Format::Ext8.as_byte(), 5u8, 7u8]);
buf.extend_from_slice(&[9u8; 5]);
let cursor = std::io::Cursor::new(buf);
let mut r = crate::io::StdReader::new(cursor);
let decoded = FixedExtension::<8>::decode(&mut r).unwrap();
assert_eq!(decoded.r#type, 7);
assert_eq!(decoded.as_slice(), &[9u8; 5]);
}
#[cfg(feature = "std")]
#[rstest::rstest]
fn extension_owned_decode_with_std_reader_copied() {
let mut buf = vec![];
buf.extend_from_slice(&[crate::Format::Ext8.as_byte(), 3u8, (!5u8) + 1]); buf.extend_from_slice(&[0xAA, 0xBB, 0xCC]);
let cursor = std::io::Cursor::new(buf);
let mut r = crate::io::StdReader::new(cursor);
let ext = super::super::ExtensionOwned::decode(&mut r).unwrap();
assert_eq!(ext.r#type, -5);
assert_eq!(ext.data, vec![0xAA, 0xBB, 0xCC]);
}
}