use crate::{
Format,
decode::{
ArrayDecoder, Decode, DecodeBorrowed, Error, MapDecoder, ReferenceDecoder, ReferenceStr,
ReferenceStrDecoder,
},
io::IoRead,
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Any<'de> {
Nil,
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
StrBorrowed(&'de str),
StrCopied(usize),
BinBorrowed(&'de [u8]),
BinCopied(usize),
Array(usize),
Map(usize),
ExtBorrowed {
r#type: i8,
data: &'de [u8],
},
ExtCopied {
r#type: i8,
len: usize,
},
}
impl<'de> DecodeBorrowed<'de> for Any<'de> {
type Value = Self;
fn decode_borrowed_with_format<R>(
format: Format,
reader: &mut R,
) -> Result<<Self as DecodeBorrowed<'de>>::Value, Error<R::Error>>
where
R: IoRead<'de>,
{
match format {
Format::Nil => Ok(Any::Nil),
Format::False | Format::True => bool::decode_with_format(format, reader).map(Any::Bool),
Format::PositiveFixInt(_) | Format::Uint8 => {
u8::decode_with_format(format, reader).map(Any::U8)
}
Format::Uint16 => u16::decode_with_format(format, reader).map(Any::U16),
Format::Uint32 => u32::decode_with_format(format, reader).map(Any::U32),
Format::Uint64 => u64::decode_with_format(format, reader).map(Any::U64),
Format::NegativeFixInt(_) | Format::Int8 => {
i8::decode_with_format(format, reader).map(Any::I8)
}
Format::Int16 => i16::decode_with_format(format, reader).map(Any::I16),
Format::Int32 => i32::decode_with_format(format, reader).map(Any::I32),
Format::Int64 => i64::decode_with_format(format, reader).map(Any::I64),
Format::Float32 => f32::decode_with_format(format, reader).map(Any::F32),
Format::Float64 => f64::decode_with_format(format, reader).map(Any::F64),
Format::FixStr(_) | Format::Str8 | Format::Str16 | Format::Str32 => {
ReferenceStrDecoder::decode_with_format(format, reader).map(|s| match s {
ReferenceStr::Borrowed(s) => Any::StrBorrowed(s),
ReferenceStr::Copied(s) => Any::StrCopied(s.len()),
})
}
Format::Bin8 | Format::Bin16 | Format::Bin32 => {
ReferenceDecoder::decode_with_format(format, reader).map(|b| match b {
crate::io::Reference::Borrowed(items) => Any::BinBorrowed(items),
crate::io::Reference::Copied(items) => Any::BinCopied(items.len()),
})
}
Format::FixExt1
| Format::FixExt2
| Format::FixExt4
| Format::FixExt8
| Format::FixExt16
| Format::Ext8
| Format::Ext16
| Format::Ext32 => {
let (length, r#type) = crate::extension::read_ext_header(format, reader)?;
reader
.read_slice(length)
.map_err(Error::Io)
.map(|data| match data {
crate::io::Reference::Borrowed(items) => Any::ExtBorrowed {
r#type,
data: items,
},
crate::io::Reference::Copied(items) => Any::ExtCopied {
r#type,
len: items.len(),
},
})
}
Format::FixArray(_) | Format::Array16 | Format::Array32 => {
ArrayDecoder::<IterCounter, Any>::decode_with_format(format, reader)
.map(|counter| Any::Array(counter.count))
}
Format::FixMap(_) | Format::Map16 | Format::Map32 => {
MapDecoder::<IterCounter, Any, Any>::decode_with_format(format, reader)
.map(|counter| Any::Map(counter.count))
}
Format::NeverUsed => Err(Error::UnexpectedFormat),
}
}
}
struct IterCounter {
count: usize,
}
impl<'de> FromIterator<Any<'de>> for IterCounter {
fn from_iter<T: IntoIterator<Item = Any<'de>>>(iter: T) -> Self {
let count = iter.into_iter().count();
Self { count }
}
}
impl<'de> FromIterator<(Any<'de>, Any<'de>)> for IterCounter {
fn from_iter<T: IntoIterator<Item = (Any<'de>, Any<'de>)>>(iter: T) -> Self {
let count = iter.into_iter().count();
Self { count }
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[rstest]
#[case(&[0xc0], Any::Nil)]
#[case(&[0xc2], Any::Bool(false))]
#[case(&[0xc3], Any::Bool(true))]
#[case(&[0x00], Any::U8(0))]
#[case(&[0x7f], Any::U8(127))]
#[case(&[0xcc, 0x80], Any::U8(128))]
#[case(&[0xcc, 0xff], Any::U8(255))]
#[case(&[0xcd, 0x01, 0x00], Any::U16(256))]
#[case(&[0xcd, 0xff, 0xff], Any::U16(65535))]
#[case(&[0xce, 0x00, 0x01, 0x00, 0x00], Any::U32(65536))]
#[case(&[0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], Any::U64(4294967296))]
#[case(&[0xff], Any::I8(-1))]
#[case(&[0xe0], Any::I8(-32))]
#[case(&[0xd0, 0xdf], Any::I8(-33))]
#[case(&[0xd0, 0x80], Any::I8(-128))]
#[case(&[0xd1, 0xff, 0x00], Any::I16(-256))]
#[case(&[0xd1, 0x80, 0x00], Any::I16(-32768))]
#[case(&[0xd2, 0xff, 0xff, 0x00, 0x00], Any::I32(-65536))]
#[case(&[0xd3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00], Any::I64(-4294967296))]
#[case(&[0xca, 0x41, 0x20, 0x00, 0x00], Any::F32(10.0))]
#[case(&[0xcb, 0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], Any::F64(10.0))]
#[case(&[0xa0], Any::StrBorrowed(""))]
#[case(&[0xa2, 0x68, 0x69], Any::StrBorrowed("hi"))]
#[case(&[0xd9, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f], Any::StrBorrowed("hello"))]
#[case(&[0xc4, 0x00], Any::BinBorrowed(&[]))]
#[case(&[0xc4, 0x03, 0x01, 0x02, 0x03], Any::BinBorrowed(&[1, 2, 3]))]
#[case(&[0x90], Any::Array(0))]
#[case(&[0x92, 0xc0, 0xc3], Any::Array(2))]
#[case(&[0x91, 0x91, 0xc0], Any::Array(1))]
#[case(&[0x80], Any::Map(0))]
#[case(&[0x81, 0x01, 0xc3], Any::Map(1))]
#[case(&[0xd4, 0x01, 0xaa], Any::ExtBorrowed { r#type: 1, data: &[0xaa] })]
#[case(&[0xd5, 0x02, 0xaa, 0xbb], Any::ExtBorrowed { r#type: 2, data: &[0xaa, 0xbb] })]
#[case(&[0xd6, 0x03, 0x01, 0x02, 0x03, 0x04], Any::ExtBorrowed { r#type: 3, data: &[1, 2, 3, 4] })]
#[case(&[0xc7, 0x00, 0x05], Any::ExtBorrowed { r#type: 5, data: &[] })]
#[case(&[0xc7, 0x03, 0x0a, 0x01, 0x02, 0x03], Any::ExtBorrowed { r#type: 10, data: &[1, 2, 3] })]
fn decode_any_ok(#[case] input: &[u8], #[case] expected: Any<'_>) {
let mut reader = crate::io::SliceReader::new(input);
let value = Any::decode(&mut reader).unwrap();
assert_eq!(value, expected);
}
#[rstest]
#[case::never_used(&[0xc1])]
fn decode_any_err(#[case] input: &[u8]) {
let mut reader = crate::io::SliceReader::new(input);
assert!(Any::decode(&mut reader).is_err());
}
}