use core::mem::MaybeUninit; use std::{rc::Rc, sync::Arc}; use bitvec::{order::Msb0, slice::BitSlice, view::AsBits}; use either::Either; use crate::{r#as::AsWrap, Error, ResultExt, StringError}; use super::{BitReader, BitReaderExt, BitUnpack}; /// Adapter to **de**serialize `T`. /// See [`as`](crate::as) module-level documentation for more. /// /// For dynamic arguments, see /// [`BitUnackAsWithArgs`](super::args::as::BitUnpackAsWithArgs). pub trait BitUnpackAs { /// Unpacks value using an adapter fn unpack_as(reader: R) -> Result where R: BitReader; } /// **De**serialize value from [`BitSlice`] using an adapter #[inline] pub fn unpack_as(bits: impl AsRef>) -> Result where As: BitUnpackAs, { bits.as_ref().unpack_as::() } /// **De**serialize value from bytes slice using an adapter #[inline] pub fn unpack_bytes_as(bytes: impl AsRef<[u8]>) -> Result where As: BitUnpackAs, { unpack_as::<_, As>(bytes.as_bits()) } /// **De**serialize value from [`BitSlice`] using an adapter /// and ensure that no more data left. #[inline] pub fn unpack_fully_as(bits: impl AsRef>) -> Result where As: BitUnpackAs, { let mut bits = bits.as_ref(); let v = bits.unpack_as::()?; if !bits.is_empty() { return Err(Error::custom("more data left")); } Ok(v) } /// **De**serialize value from bytes slice using an adapter /// and ensure that no more data left. #[inline] pub fn unpack_bytes_fully_as(bytes: impl AsRef<[u8]>) -> Result where As: BitUnpackAs, { unpack_fully_as::<_, As>(bytes.as_bits()) } impl BitUnpackAs<[T; N]> for [As; N] where As: BitUnpackAs, { #[inline] fn unpack_as(mut reader: R) -> Result<[T; N], R::Error> where R: BitReader, { let mut arr: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; for a in &mut arr { a.write(reader.unpack_as::()?); } Ok(unsafe { arr.as_ptr().cast::<[T; N]>().read() }) } } macro_rules! impl_bit_unpack_as_for_tuple { ($($n:tt:$t:ident as $a:ident),+) => { impl<$($t, $a),+> BitUnpackAs<($($t,)+)> for ($($a,)+) where $( $a: BitUnpackAs<$t>, )+ { #[inline] fn unpack_as(mut reader: R) -> Result<($($t,)+), R::Error> where R: BitReader, { Ok(($( $a::unpack_as(&mut reader) .context(concat!(".", stringify!($n)))?, )+)) } } }; } impl_bit_unpack_as_for_tuple!(0:T0 as As0); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5,6:T6 as As6); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5,6:T6 as As6,7:T7 as As7); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5,6:T6 as As6,7:T7 as As7,8:T8 as As8); impl_bit_unpack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5,6:T6 as As6,7:T7 as As7,8:T8 as As8,9:T9 as As9); impl BitUnpackAs> for Box where As: BitUnpackAs + ?Sized, { #[inline] fn unpack_as(reader: R) -> Result, R::Error> where R: BitReader, { AsWrap::::unpack(reader) .map(AsWrap::into_inner) .map(Box::new) } } impl BitUnpackAs> for Rc where As: BitUnpackAs + ?Sized, { #[inline] fn unpack_as(reader: R) -> Result, R::Error> where R: BitReader, { AsWrap::::unpack(reader) .map(AsWrap::into_inner) .map(Rc::new) } } impl BitUnpackAs> for Arc where As: BitUnpackAs + ?Sized, { #[inline] fn unpack_as(reader: R) -> Result, R::Error> where R: BitReader, { AsWrap::::unpack(reader) .map(AsWrap::into_inner) .map(Arc::new) } } /// Implementation of [`Either X Y`](https://docs.ton.org/develop/data-formats/tl-b-types#either): /// ```tlb /// left$0 {X:Type} {Y:Type} value:X = Either X Y; /// right$1 {X:Type} {Y:Type} value:Y = Either X Y; /// ``` impl BitUnpackAs> for Either where AsLeft: BitUnpackAs, AsRight: BitUnpackAs, { #[inline] fn unpack_as(reader: R) -> Result, R::Error> where R: BitReader, { Ok( Either::, AsWrap>::unpack(reader)? .map_either(AsWrap::into_inner, AsWrap::into_inner), ) } } impl BitUnpackAs> for Either<(), As> where As: BitUnpackAs, { #[inline] fn unpack_as(reader: R) -> Result, R::Error> where R: BitReader, { Ok(Either::<(), AsWrap>::unpack(reader)? .map_right(AsWrap::into_inner) .right()) } } /// Implementation of [`Maybe X`](https://docs.ton.org/develop/data-formats/tl-b-types#maybe): /// ```tlb /// nothing$0 {X:Type} = Maybe X; /// just$1 {X:Type} value:X = Maybe X; /// ``` impl BitUnpackAs> for Option where As: BitUnpackAs, { #[inline] fn unpack_as(reader: R) -> Result, R::Error> where R: BitReader, { Ok(Option::>::unpack(reader)?.map(AsWrap::into_inner)) } }