Skip to content

Commit

Permalink
refactor: deserialize Vec with args
Browse files Browse the repository at this point in the history
  • Loading branch information
mitinarseny committed Aug 20, 2024
1 parent 116c41e commit d3ef2cc
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 91 deletions.
37 changes: 35 additions & 2 deletions crates/bits/src/as/bits.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use bitvec::{order::Msb0, slice::BitSlice, view::AsBits};
use bitvec::{order::Msb0, slice::BitSlice, vec::BitVec, view::AsBits};

use crate::{
de::{r#as::BitUnpackAs, BitReader, BitReaderExt},
ser::{r#as::BitPackAs, BitPack, BitWriter, BitWriterExt},
};

use super::args::NoArgs;

/// **Ser**ialize value by taking a reference to [`BitSlice`] on it.
pub struct AsBitSlice;

Expand Down Expand Up @@ -40,6 +42,37 @@ where
/// **De**/**ser**ialize value from/into exactly `N` bits.
pub struct NBits<const BITS: usize>;

/// **De**/**ser**ialize bits by prefixing its length with `N`-bit integer.
pub struct VarBits<const BITS_FOR_LEN: usize>;

impl<const BITS_FOR_LEN: usize, T> BitPackAs<T> for VarBits<BITS_FOR_LEN>
where
T: AsRef<BitSlice<u8, Msb0>>,
{
#[inline]
fn pack_as<W>(source: &T, mut writer: W) -> Result<(), W::Error>
where
W: BitWriter,
{
let source = source.as_ref();
writer
.pack_as::<_, NBits<BITS_FOR_LEN>>(source.len())?
.pack(source)?;
Ok(())
}
}

impl<const BITS_FOR_LEN: usize> BitUnpackAs<BitVec<u8, Msb0>> for VarBits<BITS_FOR_LEN> {
#[inline]
fn unpack_as<R>(mut reader: R) -> Result<BitVec<u8, Msb0>, R::Error>
where
R: BitReader,
{
let num_bits = reader.unpack_as::<_, NBits<BITS_FOR_LEN>>()?;
reader.unpack_with(num_bits)
}
}

/// **De**/**ser**ialize bytes by prefixing its length with `N`-bit integer.
pub struct VarBytes<const BITS_FOR_BYTES_LEN: usize>;

Expand Down Expand Up @@ -67,6 +100,6 @@ impl<const BITS_FOR_BYTES_LEN: usize> BitUnpackAs<Vec<u8>> for VarBytes<BITS_FOR
R: BitReader,
{
let num_bytes = reader.unpack_as::<_, NBits<BITS_FOR_BYTES_LEN>>()?;
reader.read_bytes_vec(num_bytes)
reader.unpack_as_with::<_, Vec<NoArgs<_>>>((num_bytes, ()))
}
}
4 changes: 2 additions & 2 deletions crates/bits/src/as/integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl<const BITS: usize> BitUnpackAs<BigUint> for NBits<BITS> {
where
R: BitReader,
{
let mut bits = reader.read_bitvec(BITS)?;
let mut bits: BitVec<u8, Msb0> = reader.unpack_with(BITS)?;
let total_bits = (BITS + 7) & !7;
bits.resize(total_bits, false);
bits.shift_right(total_bits - BITS);
Expand Down Expand Up @@ -81,7 +81,7 @@ impl<const BITS: usize> BitUnpackAs<BigInt> for NBits<BITS> {
where
R: BitReader,
{
let mut bits = reader.read_bitvec(BITS)?;
let mut bits: BitVec<u8, Msb0> = reader.unpack_with(BITS)?;
let total_bits = (BITS + 7) & !7;
bits.resize(total_bits, false);
bits.shift_right(total_bits - BITS);
Expand Down
7 changes: 6 additions & 1 deletion crates/bits/src/de/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,17 @@ where
}

impl BitUnpackWithArgs for BitVec<u8, Msb0> {
/// length
type Args = usize;

#[inline]
fn unpack_with<R>(mut reader: R, len: Self::Args) -> Result<Self, R::Error>
where
R: BitReader,
{
reader.read_bitvec(len)
let mut dst = BitVec::with_capacity(len);
dst.resize(len, false);
reader.read_bits_into(&mut dst)?;
Ok(dst)
}
}
19 changes: 1 addition & 18 deletions crates/bits/src/de/reader.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::iter;

use ::bitvec::{order::Msb0, slice::BitSlice, vec::BitVec, view::AsMutBits};
use ::bitvec::{order::Msb0, slice::BitSlice, view::AsMutBits};
use impl_tools::autoimpl;

use crate::{
Expand Down Expand Up @@ -46,15 +46,6 @@ pub trait BitReader {

/// Extension helper for [`BitReader`].
pub trait BitReaderExt: BitReader {
/// Reads `n` bits and returns newly created [`BitVec`]
#[inline]
fn read_bitvec(&mut self, n: usize) -> Result<BitVec<u8, Msb0>, Self::Error> {
let mut dst = BitVec::with_capacity(n);
dst.resize(n, false);
self.read_bits_into(&mut dst)?;
Ok(dst)
}

/// Reads `dst.len()` bytes into given byte slice
#[inline]
fn read_bytes_into(&mut self, mut dst: impl AsMut<[u8]>) -> Result<(), Self::Error> {
Expand All @@ -69,14 +60,6 @@ pub trait BitReaderExt: BitReader {
Ok(arr)
}

/// Read `n` bytes and return [`Vec`]
#[inline]
fn read_bytes_vec(&mut self, n: usize) -> Result<Vec<u8>, Self::Error> {
let mut v = vec![0; n];
self.read_bytes_into(&mut v)?;
Ok(v)
}

/// Unpack value using its [`BitUnpack`] implementation
#[inline]
fn unpack<T>(&mut self) -> Result<T, Self::Error>
Expand Down
69 changes: 47 additions & 22 deletions crates/contracts/src/wallet/v5r1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use tlb::{
de::{CellDeserialize, CellParser, CellParserError},
r#as::{Data, NoArgs},
ser::{CellBuilder, CellBuilderError, CellSerialize},
Cell, Error,
Cell, Error, ResultExt,
};
use tlb_ton::{
action::{OutAction, SendMsgAction},
Expand Down Expand Up @@ -67,7 +67,7 @@ impl WalletVersion for V5R1 {
msg_seqno,
inner: WalletV5R1InnerRequest {
out_actions: msgs.into_iter().map(OutAction::SendMsg).collect(),
other_actions: [].into(),
extended: [].into(),
},
}
}
Expand Down Expand Up @@ -126,7 +126,7 @@ impl<'de> CellDeserialize<'de> for WalletV5R1Data {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WalletV5R1InnerRequest {
pub out_actions: Vec<OutAction>,
pub other_actions: Vec<ExtendedAction>,
pub extended: Vec<ExtendedAction>,
}

impl CellSerialize for WalletV5R1InnerRequest {
Expand All @@ -135,18 +135,22 @@ impl CellSerialize for WalletV5R1InnerRequest {
.store_as::<_, Option<&List>>(
Some(&self.out_actions).filter(|actions| !actions.is_empty()),
)?
.store_as::<_, Option<&List>>(
Some(&self.other_actions).filter(|other| !other.is_empty()),
)?;
.store_as::<_, Option<&List>>(Some(&self.extended).filter(|other| !other.is_empty()))?;
Ok(())
}
}

impl<'de> CellDeserialize<'de> for WalletV5R1InnerRequest {
fn parse(parser: &mut CellParser<'de>) -> Result<Self, CellParserError<'de>> {
Ok(Self {
out_actions: parser.parse_as::<_, Option<List>>()?.unwrap_or_default(),
other_actions: parser.parse_as::<_, Option<List>>()?.unwrap_or_default(),
out_actions: parser
.parse_as::<_, Option<List>>()
.context("out_actions")?
.unwrap_or_default(),
extended: parser
.parse_as::<_, Option<List>>()
.context("extended")?
.unwrap_or_default(),
})
}
}
Expand Down Expand Up @@ -288,10 +292,7 @@ pub enum WalletV5R1MsgBody {
/// ```tlb
/// internal_extension#6578746e query_id:(## 64) inner:InnerRequest = InternalMsgBody;
/// ```
InternalExtension {
query_id: u64,
inner: WalletV5R1InnerRequest,
},
InternalExtension(InternalExtensionWalletV5R1MsgBody),

/// ```tlb
/// external_signed#7369676e signed:SignedRequest = ExternalMsgBody;
Expand All @@ -309,10 +310,9 @@ impl CellSerialize for WalletV5R1MsgBody {
fn store(&self, builder: &mut CellBuilder) -> Result<(), CellBuilderError> {
match self {
Self::InternalSigned(msg) => builder.pack(Self::INTERNAL_SIGNED_PREFIX)?.store(msg)?,
Self::InternalExtension { query_id, inner } => builder
.pack(Self::INTERNAL_EXTENSION_PREFIX)?
.pack(query_id)?
.store(inner)?,
Self::InternalExtension(msg) => {
builder.pack(Self::INTERNAL_EXTENSION_PREFIX)?.store(msg)?
}
Self::ExternalSigned(msg) => builder.pack(Self::EXTERNAL_SIGNED_PREFIX)?.store(msg)?,
};
Ok(())
Expand All @@ -322,17 +322,42 @@ impl CellSerialize for WalletV5R1MsgBody {
impl<'de> CellDeserialize<'de> for WalletV5R1MsgBody {
fn parse(parser: &mut CellParser<'de>) -> Result<Self, CellParserError<'de>> {
Ok(match parser.unpack()? {
Self::INTERNAL_SIGNED_PREFIX => Self::InternalSigned(parser.parse()?),
Self::INTERNAL_EXTENSION_PREFIX => Self::InternalExtension {
query_id: parser.unpack()?,
inner: parser.parse()?,
},
Self::EXTERNAL_SIGNED_PREFIX => Self::ExternalSigned(parser.parse()?),
Self::INTERNAL_SIGNED_PREFIX => {
Self::InternalSigned(parser.parse().context("internal_signed")?)
}
Self::INTERNAL_EXTENSION_PREFIX => {
Self::InternalExtension(parser.parse().context("internal_extension")?)
}
Self::EXTERNAL_SIGNED_PREFIX => {
Self::ExternalSigned(parser.parse().context("external_signed")?)
}
prefix => return Err(Error::custom(format!("unknown prefix: {prefix:#0x}"))),
})
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InternalExtensionWalletV5R1MsgBody {
query_id: u64,
inner: WalletV5R1InnerRequest,
}

impl CellSerialize for InternalExtensionWalletV5R1MsgBody {
fn store(&self, builder: &mut CellBuilder) -> Result<(), CellBuilderError> {
builder.pack(self.query_id)?.store(&self.inner)?;
Ok(())
}
}

impl<'de> CellDeserialize<'de> for InternalExtensionWalletV5R1MsgBody {
fn parse(parser: &mut CellParser<'de>) -> Result<Self, CellParserError<'de>> {
Ok(Self {
query_id: parser.unpack()?,
inner: parser.parse()?,
})
}
}

#[cfg(test)]
mod tests {
use tlb::bits::{de::unpack_fully, ser::pack_with};
Expand Down
26 changes: 20 additions & 6 deletions crates/tlb-ton/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use tlb::{
de::{CellDeserialize, CellParser, CellParserError},
r#as::Ref,
ser::{CellBuilder, CellBuilderError, CellSerialize},
Cell, Error,
Cell, Error, ResultExt,
};

use crate::{currency::CurrencyCollection, library::LibRef, message::Message};
Expand Down Expand Up @@ -39,6 +39,7 @@ impl OutAction {
}

impl CellSerialize for OutAction {
#[inline]
fn store(&self, builder: &mut CellBuilder) -> Result<(), CellBuilderError> {
match self {
OutAction::SendMsg(action) => builder.pack(Self::SEND_MSG_PREFIX)?.store(action)?,
Expand All @@ -57,12 +58,19 @@ impl CellSerialize for OutAction {
}

impl<'de> CellDeserialize<'de> for OutAction {
#[inline]
fn parse(parser: &mut CellParser<'de>) -> Result<Self, CellParserError<'de>> {
Ok(match parser.unpack()? {
Self::SEND_MSG_PREFIX => Self::SendMsg(parser.parse()?),
Self::SET_CODE_PREFIX => Self::SetCode(parser.parse_as::<_, Ref>()?),
Self::RESERVE_CURRENCY_PREFIX => Self::ReserveCurrency(parser.parse()?),
Self::CHANGE_LIBRARY_PREFIX => Self::ChangeLibrary(parser.parse()?),
Self::SEND_MSG_PREFIX => Self::SendMsg(parser.parse().context("action_send_msg")?),
Self::SET_CODE_PREFIX => {
Self::SetCode(parser.parse_as::<_, Ref>().context("action_set_code")?)
}
Self::RESERVE_CURRENCY_PREFIX => {
Self::ReserveCurrency(parser.parse().context("action_reserve_currency")?)
}
Self::CHANGE_LIBRARY_PREFIX => {
Self::ChangeLibrary(parser.parse().context("action_change_library")?)
}
prefix => return Err(Error::custom(format!("unknown prefix {prefix:#0x}"))),
})
}
Expand All @@ -84,6 +92,7 @@ where
IC: CellSerialize,
ID: CellSerialize,
{
#[inline]
fn store(&self, builder: &mut CellBuilder) -> Result<(), CellBuilderError> {
builder.pack(self.mode)?.store_as::<_, Ref>(&self.message)?;
Ok(())
Expand All @@ -96,10 +105,11 @@ where
IC: CellDeserialize<'de>,
ID: CellDeserialize<'de>,
{
#[inline]
fn parse(parser: &mut CellParser<'de>) -> Result<Self, CellParserError<'de>> {
Ok(Self {
mode: parser.unpack()?,
message: parser.parse()?,
message: parser.parse_as::<_, Ref>()?,
})
}
}
Expand All @@ -114,13 +124,15 @@ pub struct ReserveCurrencyAction {
}

impl CellSerialize for ReserveCurrencyAction {
#[inline]
fn store(&self, builder: &mut CellBuilder) -> Result<(), CellBuilderError> {
builder.pack(self.mode)?.store(&self.currency)?;
Ok(())
}
}

impl<'de> CellDeserialize<'de> for ReserveCurrencyAction {
#[inline]
fn parse(parser: &mut CellParser<'de>) -> Result<Self, CellParserError<'de>> {
Ok(Self {
mode: parser.unpack()?,
Expand All @@ -142,6 +154,7 @@ impl<R> CellSerialize for ChangeLibraryAction<R>
where
R: CellSerialize,
{
#[inline]
fn store(&self, builder: &mut CellBuilder) -> Result<(), CellBuilderError> {
builder
.pack_as::<_, NBits<7>>(self.mode)?
Expand All @@ -154,6 +167,7 @@ impl<'de, R> CellDeserialize<'de> for ChangeLibraryAction<R>
where
R: CellDeserialize<'de>,
{
#[inline]
fn parse(parser: &mut CellParser<'de>) -> Result<Self, CellParserError<'de>> {
Ok(Self {
mode: parser.unpack_as::<_, NBits<7>>()?,
Expand Down
Loading

0 comments on commit d3ef2cc

Please sign in to comment.