Skip to content

Commit

Permalink
feat: optimize EitherInlineOrRef
Browse files Browse the repository at this point in the history
  • Loading branch information
mitinarseny committed Aug 30, 2024
1 parent 1c919d1 commit 9e2de89
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 21 deletions.
57 changes: 56 additions & 1 deletion crates/bits/src/ser/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub trait BitWriter {
// An error ocurred while writing
type Error: Error;

/// Returns remaining capacity in bits
fn capacity_left(&self) -> usize;

/// Writes a single bit.
fn write_bit(&mut self, bit: bool) -> Result<(), Self::Error>;

Expand Down Expand Up @@ -216,12 +219,43 @@ pub trait BitWriterExt: BitWriter {
}
impl<T> BitWriterExt for T where T: BitWriter {}

struct NoopBitWriter;

impl BitWriter for NoopBitWriter {
type Error = StringError;

#[inline]
fn capacity_left(&self) -> usize {
usize::MAX
}

#[inline]
fn write_bit(&mut self, _bit: bool) -> Result<(), Self::Error> {
Ok(())
}

#[inline]
fn write_bitslice(&mut self, _bits: &BitSlice<u8, Msb0>) -> Result<(), Self::Error> {
Ok(())
}

#[inline]
fn repeat_bit(&mut self, _n: usize, _bit: bool) -> Result<(), Self::Error> {
Ok(())
}
}

impl<W> BitWriter for BitCounter<W>
where
W: BitWriter,
{
type Error = W::Error;

#[inline]
fn capacity_left(&self) -> usize {
self.inner.capacity_left()
}

#[inline]
fn write_bit(&mut self, bit: bool) -> Result<(), Self::Error> {
self.inner.write_bit(bit)?;
Expand Down Expand Up @@ -265,7 +299,7 @@ where

#[inline]
fn ensure_more(&self, n: usize) -> Result<(), W::Error> {
if self.bit_count() + n > self.limit {
if self.capacity_left() < n {
return Err(Error::custom("max bits limit reached"));
}
Ok(())
Expand All @@ -283,6 +317,11 @@ where
{
type Error = W::Error;

#[inline]
fn capacity_left(&self) -> usize {
(self.limit - self.bit_count()).min(self.inner.capacity_left())
}

#[inline]
fn write_bit(&mut self, bit: bool) -> Result<(), Self::Error> {
self.ensure_more(1)?;
Expand All @@ -309,6 +348,11 @@ where
{
type Error = T::Error;

#[inline]
fn capacity_left(&self) -> usize {
self.inner.capacity_left().min(self.writer.capacity_left())
}

#[inline]
fn write_bit(&mut self, bit: bool) -> Result<(), Self::Error> {
self.inner.write_bit(bit)?;
Expand Down Expand Up @@ -343,6 +387,11 @@ where
{
type Error = StringError;

#[inline]
fn capacity_left(&self) -> usize {
usize::MAX - self.len()
}

#[inline]
fn write_bit(&mut self, bit: bool) -> Result<(), Self::Error> {
self.push(bit);
Expand All @@ -366,6 +415,12 @@ where
impl BitWriter for String {
type Error = StringError;

#[inline]
fn capacity_left(&self) -> usize {
usize::MAX - self.len()
}

#[inline]
fn write_bit(&mut self, bit: bool) -> Result<(), Self::Error> {
self.push(if bit { '1' } else { '0' });
Ok(())
Expand Down
11 changes: 4 additions & 7 deletions crates/contracts/src/jetton/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use tlb::{
},
de::{CellDeserialize, CellParser, CellParserError},
either::Either,
r#as::{ParseFully, Ref, Same},
ser::{CellBuilder, CellBuilderError, CellSerialize, CellSerializeExt},
r#as::{EitherInlineOrRef, ParseFully, Ref, Same},
ser::{CellBuilder, CellBuilderError, CellSerialize},
Cell, Error,
};
use tlb_ton::MsgAddress;
Expand Down Expand Up @@ -56,11 +56,8 @@ where
// forward_ton_amount:(VarUInteger 16)
.pack_as::<_, &VarInt<4>>(&self.forward_ton_amount)?
// forward_payload:(Either Cell ^Cell)
.store_as::<_, Either<(), Ref>>(
Some(&self.forward_payload.to_cell()?)
// store empty cell inline
.filter(|cell| !cell.is_empty()),
)?;
.store_as::<_, EitherInlineOrRef>(&self.forward_payload)?;

Ok(())
}
}
Expand Down
5 changes: 0 additions & 5 deletions crates/contracts/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,6 @@ where
/// ).unwrap();
/// # let mut b = Cell::builder();
/// # b.store(msg).unwrap();
/// # let cell = b.into_cell();
/// # assert_eq!(
/// # hex!("607b41a4b219fbc6d23f4aae5c4b85e5ceca07bc0ba732ae02a621588f0577d4"),
///# cell.hash(),
/// # );
/// ```
#[inline]
pub fn create_external_message(
Expand Down
10 changes: 3 additions & 7 deletions crates/tlb-ton/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use tlb::{
},
de::{CellDeserialize, CellParser, CellParserError},
either::Either,
r#as::{DefaultOnNone, Ref, Same},
r#as::{DefaultOnNone, EitherInlineOrRef, Ref, Same},
ser::{CellBuilder, CellBuilderError, CellSerialize, CellSerializeExt},
Cell, ResultExt,
};
Expand Down Expand Up @@ -77,12 +77,8 @@ where
fn store(&self, builder: &mut CellBuilder) -> Result<(), CellBuilderError> {
builder
.store(&self.info)?
.store_as::<_, Option<Either<(), Ref>>>(self.init.as_ref().map(Some))?
.store_as::<_, Either<(), Ref>>(
Some(self.body.to_cell()?)
// store empty cell inline
.filter(|cell| !cell.is_empty()),
)?;
.store_as::<_, &Option<EitherInlineOrRef>>(&self.init)?
.store_as::<_, EitherInlineOrRef>(&self.body)?;
Ok(())
}
}
Expand Down
70 changes: 69 additions & 1 deletion crates/tlb/src/as/reference.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use core::marker::PhantomData;

use tlbits::{either::Either, r#as::args::NoArgs, ser::BitWriter};

use crate::{
de::{
args::r#as::CellDeserializeAsWithArgs, r#as::CellDeserializeAs, CellParser, CellParserError,
},
ser::{
args::r#as::CellSerializeAsWithArgs, r#as::CellSerializeAs, CellBuilder, CellBuilderError,
},
ResultExt,
Cell, ResultExt,
};

use super::Same;
Expand Down Expand Up @@ -68,3 +70,69 @@ where
parser.parse_reference_as_with::<T, As>(args).context("^")
}
}

/// ```tlb
/// {X:Type} Either X ^X = EitherInlineOrRef X
/// ```
pub struct EitherInlineOrRef<As: ?Sized = Same>(PhantomData<As>);

impl<T, As> CellSerializeAs<T> for EitherInlineOrRef<As>
where
As: CellSerializeAs<T>,
{
#[inline]
fn store_as(source: &T, builder: &mut CellBuilder) -> Result<(), CellBuilderError> {
EitherInlineOrRef::<NoArgs<(), As>>::store_as_with(source, builder, ())
}
}

impl<T, As> CellSerializeAsWithArgs<T> for EitherInlineOrRef<As>
where
As: CellSerializeAsWithArgs<T>,
{
type Args = As::Args;

#[inline]
fn store_as_with(
source: &T,
builder: &mut CellBuilder,
args: Self::Args,
) -> Result<(), CellBuilderError> {
let mut b = Cell::builder();
As::store_as_with(source, &mut b, args)?;
let cell = b.into_cell();
builder.store_as::<_, Either<Same, Ref>>(
if cell.data.len() <= builder.capacity_left() {
Either::Left
} else {
Either::Right
}(cell),
)?;
Ok(())
}
}

impl<'de, T, As> CellDeserializeAs<'de, T> for EitherInlineOrRef<As>
where
As: CellDeserializeAs<'de, T>,
{
#[inline]
fn parse_as(parser: &mut CellParser<'de>) -> Result<T, CellParserError<'de>> {
EitherInlineOrRef::<NoArgs<(), As>>::parse_as_with(parser, ())
}
}

impl<'de, T, As> CellDeserializeAsWithArgs<'de, T> for EitherInlineOrRef<As>
where
As: CellDeserializeAsWithArgs<'de, T>,
{
type Args = As::Args;

#[inline]
fn parse_as_with(
parser: &mut CellParser<'de>,
args: Self::Args,
) -> Result<T, CellParserError<'de>> {
Either::<As, Ref<As>>::parse_as_with(parser, args).map(Either::into_inner)
}
}
5 changes: 5 additions & 0 deletions crates/tlb/src/ser/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ impl CellBuilder {
impl BitWriter for CellBuilder {
type Error = <CellBitWriter as BitWriter>::Error;

#[inline]
fn capacity_left(&self) -> usize {
self.data.capacity_left()
}

#[inline]
fn write_bit(&mut self, bit: bool) -> Result<(), Self::Error> {
self.data.write_bit(bit)?;
Expand Down

0 comments on commit 9e2de89

Please sign in to comment.