#[allow(unused)]
macro_rules! impl_read_list {
(
$ty:ident<T $(: $tbound0:ident $(+ $tbound1:ident)?)?
$(, $h:ident: $hbound0:ident + $hbound1:ident)?>,
$new:expr,
$push:ident
) => {
impl<Tag, Ctx, T, $($h)?> $crate::BitDecode<Ctx, $crate::Tag<Tag>> for $ty<T, $($h)?>
where
T: $crate::BitDecode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?,
Tag: ::core::convert::TryInto<usize>,
$($h: $hbound0 + $hbound1)?
{
fn decode<R, E>(
read: &mut R,
ctx: &mut Ctx,
tag: $crate::Tag<Tag>,
) -> $crate::Result<Self>
where
R: ::bitstream_io::BitRead,
E: ::bitstream_io::Endianness,
{
let item_count = ::core::convert::TryInto::try_into(tag.0)
.map_err(|_| $crate::Error::TagConvert)?;
let mut this = ($new)(item_count);
for _ in 0..item_count {
this.$push($crate::BitDecode::<_, _>::decode::<_, E>(read, ctx, ())?);
}
::core::result::Result::Ok(this)
}
}
impl<Ctx, T, $($h)?> $crate::BitDecode<Ctx, $crate::Untagged> for $ty<T, $($h)?>
where
T: $crate::BitDecode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?,
$($h: $hbound0 + $hbound1)?
{
fn decode<R, E>(
read: &mut R,
ctx: &mut Ctx,
_: $crate::Untagged,
) -> $crate::Result<Self>
where
R: ::bitstream_io::BitRead,
E: ::bitstream_io::Endianness,
{
$crate::util::decode_items_to_eof::<_, E, _, _>(read, ctx).collect()
}
}
#[cfg(feature = "prepend-tags")]
impl<Ctx, T, $($h)?> $crate::BitDecode<Ctx> for $ty<T, $($h)?>
where
T: $crate::BitDecode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?,
$($h: $hbound0 + $hbound1)?
{
fn decode<R, E>(
read: &mut R,
ctx: &mut Ctx,
(): (),
) -> $crate::Result<Self>
where
R: ::bitstream_io::BitRead,
E: ::bitstream_io::Endianness,
{
let tag: usize = $crate::BitDecode::decode::<_, E>(read, ctx, ())?;
$crate::BitDecode::decode::<_, E>(read, ctx, $crate::Tag(tag))
}
}
}
}
#[allow(unused)]
macro_rules! impl_write_list {
($ty:ident<T $(: $tbound0:ident $(+ $tbound1:ident)?)? $(, $h:ident)?> ) => {
impl<Ctx, T, $($h)?> $crate::BitEncode<Ctx, $crate::Untagged> for $ty<T, $($h)?>
where
T: $crate::BitEncode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?
{
fn encode<W, E>(&self,
write: &mut W,
ctx: &mut Ctx,
_: $crate::Untagged,
) -> $crate::Result<()>
where
W: ::bitstream_io::BitWrite,
E: ::bitstream_io::Endianness,
{
$crate::util::encode_items::<_, E, _, _>(self.iter(), write, ctx)
}
}
#[cfg(feature = "prepend-tags")]
impl<Ctx, T, $($h)?> $crate::BitEncode<Ctx> for $ty<T, $($h)?>
where
T: $crate::BitEncode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?
{
fn encode<W, E>(&self,
write: &mut W,
ctx: &mut Ctx,
(): (),
) -> $crate::Result<()>
where
W: ::bitstream_io::BitWrite,
E: ::bitstream_io::Endianness,
{
$crate::BitEncode::encode::<_, E>(&self.len(), write, ctx, ())?;
$crate::BitEncode::encode::<_, E>(self, write, ctx, $crate::Untagged)
}
}
}
}
#[cfg(feature = "alloc")]
mod vec {
use alloc::vec::Vec;
impl_read_list!(Vec<T>, |n| Self::with_capacity(n), push);
impl_write_list!(Vec<T>);
#[cfg(test)]
mod tests {
use crate::{Tag, Untagged};
use super::*;
test_untagged_and_codec!(
Vec<u8>| Untagged, Tag(3); alloc::vec![1, 2, 3] => [0x01, 0x02, 0x03]
);
#[cfg(feature = "prepend-tags")]
test_roundtrip!(Vec::<i32>);
}
}
#[cfg(feature = "alloc")]
mod linked_list {
use alloc::collections::linked_list::LinkedList;
impl_read_list!(LinkedList<T>, |_| Self::new(), push_back);
impl_write_list!(LinkedList<T>);
#[cfg(test)]
mod tests {
use crate::{Tag, Untagged};
use super::*;
test_untagged_and_codec!(
LinkedList<u8>| Untagged, Tag(3); [1, 2, 3].into() => [0x01, 0x02, 0x03]
);
#[cfg(feature = "prepend-tags")]
test_roundtrip!(LinkedList::<i32>);
}
}
#[cfg(feature = "alloc")]
mod vec_deque {
use alloc::collections::vec_deque::VecDeque;
impl_read_list!(VecDeque<T>, |n| Self::with_capacity(n), push_back);
impl_write_list!(VecDeque<T>);
#[cfg(test)]
mod tests {
use crate::{Tag, Untagged};
use super::*;
test_untagged_and_codec!(
VecDeque<u8>| Untagged, Tag(3); [1, 2, 3].into() => [0x01, 0x02, 0x03]
);
#[cfg(feature = "prepend-tags")]
test_roundtrip!(VecDeque::<i32>);
}
}
#[cfg(feature = "alloc")]
mod b_tree_set {
use alloc::collections::btree_set::BTreeSet;
impl_read_list!(BTreeSet<T: Ord>, |_| Self::new(), insert);
impl_write_list!(BTreeSet<T: Ord>);
#[cfg(test)]
mod tests {
use crate::{Tag, Untagged};
use super::*;
test_untagged_and_codec!(
BTreeSet<u8>| Untagged, Tag(3); [1, 2, 3].into() => [0x01, 0x02, 0x03]
);
#[cfg(feature = "prepend-tags")]
test_roundtrip!(BTreeSet::<i32>);
}
}
#[cfg(feature = "alloc")]
mod binary_heap {
use alloc::collections::binary_heap::BinaryHeap;
impl_read_list!(BinaryHeap<T: Ord>, |n| Self::with_capacity(n), push);
impl_write_list!(BinaryHeap<T: Ord>);
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use bitstream_io::{BigEndian, BitReader};
use crate::{BitDecode, Tag, Untagged};
use super::*;
#[test]
fn decode() {
let bytes: &[u8] = &[0x01];
let exp: BinaryHeap<u8> = [1].into();
let read: BinaryHeap<u8> = BitDecode::decode::<_, BigEndian>(
&mut BitReader::endian(bytes, BigEndian),
&mut (),
Tag(1),
)
.unwrap();
assert_eq!(
exp.into_iter().collect::<Vec<_>>(),
read.into_iter().collect::<Vec<_>>()
);
}
test_encode!(BinaryHeap<u8>| Untagged; [1].into() => [0x01]);
}
}
#[cfg(feature = "std")]
mod hash_set {
use core::hash::{BuildHasher, Hash};
use std::collections::HashSet;
impl_read_list!(HashSet<T: Hash + Eq, H: BuildHasher + Default>, |n| Self::with_capacity_and_hasher(n, H::default()), insert);
impl_write_list!(HashSet<T: Hash + Eq, H>);
#[cfg(test)]
mod tests {
use crate::{Tag, Untagged};
use super::*;
test_untagged_and_codec!(HashSet<u8>| Untagged, Tag(1); [1].into() => [0x01]);
#[cfg(feature = "prepend-tags")]
test_roundtrip!(HashSet::<i32>);
}
}