use std::{borrow::Cow, rc::Rc, sync::Arc};
use bitvec::{order::Msb0, vec::BitVec};
use either::Either;
use crate::{
StringError,
r#as::{AsWrap, Same},
};
use super::{BitPack, BitWriter, BitWriterExt};
pub trait BitPackAs<T: ?Sized> {
type Args;
fn pack_as<W>(source: &T, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized;
}
#[inline]
pub fn pack_as<T, As>(value: T, args: As::Args) -> Result<BitVec<u8, Msb0>, StringError>
where
As: BitPackAs<T> + ?Sized,
{
let mut writer = BitVec::new();
writer.pack_as::<_, As>(value, args)?;
Ok(writer)
}
impl<'a, T, As> BitPackAs<&'a T> for &'a As
where
As: BitPackAs<T> + ?Sized,
T: ?Sized,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &&'a T, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
AsWrap::<&T, As>::new(source).pack(writer, args)
}
}
impl<'a, T, As> BitPackAs<&'a mut T> for &'a mut As
where
As: BitPackAs<T> + ?Sized,
T: ?Sized,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &&'a mut T, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
AsWrap::<&T, As>::new(source).pack(writer, args)
}
}
impl<T, As> BitPackAs<[T]> for [As]
where
As: BitPackAs<T>,
As::Args: Clone,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &[T], writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
writer.pack_many_as::<_, &As>(source, args)?;
Ok(())
}
}
impl<T, As, const N: usize> BitPackAs<[T; N]> for [As; N]
where
As: BitPackAs<T>,
As::Args: Clone,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &[T; N], writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
<[As]>::pack_as(source.as_slice(), writer, args)
}
}
macro_rules! impl_bit_pack_as_for_tuple {
($($t:ident as $a:ident:$n:tt),*) => {
impl<$($t, $a),*> BitPackAs<($($t,)*)> for ($($a,)*)
where $(
$a: BitPackAs<$t>,
)*
{
type Args = ($($a::Args,)*);
#[inline]
#[allow(unused_variables)]
fn pack_as<W>(source: &($($t,)*), writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{$(
$a::pack_as(&source.$n, writer, args.$n)?;)*
Ok(())
}
}
};
}
impl_bit_pack_as_for_tuple!();
impl_bit_pack_as_for_tuple!(T0 as As0:0);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5,T6 as As6:6);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5,T6 as As6:6,T7 as As7:7);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5,T6 as As6:6,T7 as As7:7,T8 as As8:8);
impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5,T6 as As6:6,T7 as As7:7,T8 as As8:8,T9 as As9:9);
impl<T, As> BitPackAs<Rc<T>> for Box<As>
where
As: BitPackAs<T> + ?Sized,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &Rc<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
AsWrap::<&T, As>::new(source).pack(writer, args)
}
}
impl<T, As> BitPackAs<Rc<T>> for Rc<As>
where
As: BitPackAs<T> + ?Sized,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &Rc<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
AsWrap::<&T, As>::new(source).pack(writer, args)
}
}
impl<T, As> BitPackAs<Arc<T>> for Arc<As>
where
As: BitPackAs<T> + ?Sized,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &Arc<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
AsWrap::<&T, As>::new(source).pack(writer, args)
}
}
impl<'a, T, As> BitPackAs<Cow<'a, T>> for Cow<'a, As>
where
T: ToOwned + ?Sized,
As: ToOwned + BitPackAs<T> + ?Sized,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &Cow<'a, T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
AsWrap::<&T, As>::new(source).pack(writer, args)
}
}
impl<Left, Right, AsLeft, AsRight> BitPackAs<Either<Left, Right>> for Either<AsLeft, AsRight>
where
AsLeft: BitPackAs<Left>,
AsRight: BitPackAs<Right>,
{
type Args = (AsLeft::Args, AsRight::Args);
#[inline]
fn pack_as<W>(
source: &Either<Left, Right>,
writer: &mut W,
args: Self::Args,
) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
source
.as_ref()
.map_either(AsWrap::<&Left, AsLeft>::new, AsWrap::<&Right, AsRight>::new)
.pack(writer, args)
}
}
impl<T, As> BitPackAs<Option<T>> for Either<(), As>
where
As: BitPackAs<T>,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &Option<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
Either::<Same, &As>::pack_as(
&match source.as_ref() {
None => Either::Left(()),
Some(v) => Either::Right(v),
},
writer,
((), args),
)
}
}
impl<T, As> BitPackAs<Option<T>> for Option<As>
where
As: BitPackAs<T>,
{
type Args = As::Args;
#[inline]
fn pack_as<W>(source: &Option<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
source
.as_ref()
.map(AsWrap::<&T, As>::new)
.pack(writer, args)
}
}
pub trait BitPackWrapAsExt {
#[inline]
fn wrap_as<As>(&self) -> AsWrap<&'_ Self, As>
where
As: BitPackAs<Self> + ?Sized,
{
AsWrap::new(self)
}
}
impl<T> BitPackWrapAsExt for T {}