Skip to content

Commit

Permalink
Add as_data_slice to builder to prevent building intermediate cells
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Aug 15, 2023
1 parent 585c502 commit ddcafea
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 259 deletions.
80 changes: 78 additions & 2 deletions src/cell/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::sync::Arc;

use crate::cell::finalizer::{CellParts, DefaultFinalizer, Finalizer};
use crate::cell::{
Cell, CellDescriptor, CellSlice, CellType, DynCell, HashBytes, LevelMask, MAX_BIT_LEN,
MAX_REF_COUNT,
Cell, CellDescriptor, CellImpl, CellSlice, CellType, DynCell, HashBytes, LevelMask,
MAX_BIT_LEN, MAX_REF_COUNT,
};
use crate::error::Error;
use crate::util::{ArrayVec, Bitstring};
Expand Down Expand Up @@ -292,6 +292,14 @@ impl CellBuilder {
Ok(res)
}

/// Returns a slice which contains only builder data bits and no references.
///
/// NOTE: intermediate cell hash is undefined.
pub fn as_data_slice(&self) -> CellSlice<'_> {
// SAFETY: we interpret cell builder data as ordinary cell
unsafe { CellSlice::new_unchecked(IntermediateDataCell::wrap(self)) }
}

/// Returns an underlying cell data.
#[inline]
pub fn raw_data(&self) -> &[u8; 128] {
Expand Down Expand Up @@ -983,6 +991,74 @@ impl CellRefsBuilder {
}
}

#[repr(transparent)]
struct IntermediateDataCell(CellBuilder);

impl IntermediateDataCell {
#[inline(always)]
const fn wrap(value: &CellBuilder) -> &Self {
// SAFETY: IntermediateDataCell is #[repr(transparent)]
unsafe { &*(value as *const CellBuilder as *const Self) }
}
}

impl CellImpl for IntermediateDataCell {
fn descriptor(&self) -> CellDescriptor {
CellDescriptor {
d1: 0,
d2: CellDescriptor::compute_d2(self.0.bit_len),
}
}

fn data(&self) -> &[u8] {
self.0.raw_data()
}

fn bit_len(&self) -> u16 {
self.0.bit_len
}

fn reference(&self, _: u8) -> Option<&DynCell> {
None
}

fn reference_cloned(&self, _: u8) -> Option<Cell> {
None
}

fn virtualize(&self) -> &DynCell {
self
}

fn hash(&self, _: u8) -> &HashBytes {
panic!("Hash for an intermediate data cell is not defined");
}

fn depth(&self, _: u8) -> u16 {
0
}

fn take_first_child(&mut self) -> Option<Cell> {
None
}

fn replace_first_child(&mut self, parent: Cell) -> Result<Cell, Cell> {
Err(parent)
}

fn take_next_child(&mut self) -> Option<Cell> {
None
}

#[cfg(feature = "stats")]
fn stats(&self) -> CellTreeStats {
CellTreeStats {
bit_count: self.0.bit_len as u64,
cell_count: 1,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
20 changes: 1 addition & 19 deletions src/dict/aug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,12 @@ where
K: Store + DictKey,
{
/// Returns the value corresponding to the key.
///
/// Key is serialized using the default finalizer.
pub fn get<'a: 'b, 'b, Q>(&'a self, key: Q) -> Result<Option<(A, V)>, Error>
where
Q: Borrow<K> + 'b,
(A, V): Load<'a>,
{
self.dict.get_ext(key, &mut Cell::default_finalizer())
self.dict.get(key)
}
}

Expand Down Expand Up @@ -335,22 +333,6 @@ impl<K, A, V> AugDict<K, A, V>
where
K: Store + DictKey,
{
/// Returns the augmented value corresponding to the key.
///
/// Key is serialized using the provided finalizer.
pub fn get_ext<'a: 'b, 'b, Q>(
&'a self,
key: Q,
finalizer: &mut dyn Finalizer,
) -> Result<Option<(A, V)>, Error>
where
Q: Borrow<K> + 'b,
A: Load<'a>,
V: Load<'a>,
{
self.dict.get_ext(key, finalizer)
}

/// Gets an iterator over the raw entries of the dictionary, sorted by key.
/// The iterator element type is `Result<(CellBuilder, CellSlice)>`.
///
Expand Down
6 changes: 0 additions & 6 deletions src/dict/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1209,12 +1209,6 @@ fn read_hml_same<'a>(label: &mut CellSlice<'a>, bits_for_len: u16) -> Result<Cel
Ok(slice.get_prefix(len, 0))
}

fn serialize_entry<T: Store>(entry: &T, finalizer: &mut dyn Finalizer) -> Result<Cell, Error> {
let mut builder = CellBuilder::new();
ok!(entry.store_into(&mut builder, finalizer));
builder.build_ext(finalizer)
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum Branch {
// Branch for a key part that starts with bit 0
Expand Down
60 changes: 60 additions & 0 deletions src/dict/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,18 @@ impl<'a> RawOwnedIter<'a> {
self.inner.signed = true;
self
}

/// Returns whether the iterator direction was reversed.
#[inline]
pub fn is_reversed(&self) -> bool {
self.inner.reversed
}

/// Returns whether the iterator treats keys as signed integers.
#[inline]
pub fn is_signed(&self) -> bool {
self.inner.signed
}
}

impl<'a> Iterator for RawOwnedIter<'a> {
Expand Down Expand Up @@ -576,6 +588,18 @@ impl<'a> RawIter<'a> {
self
}

/// Returns whether the iterator direction was reversed.
#[inline]
pub fn is_reversed(&self) -> bool {
self.reversed
}

/// Returns whether the iterator treats keys as signed integers.
#[inline]
pub fn is_signed(&self) -> bool {
self.signed
}

/// Advances the iterator and returns the next value as owned cell slice parts.
pub fn next_owned(
&mut self,
Expand Down Expand Up @@ -783,6 +807,18 @@ impl<'a> RawKeys<'a> {
self.inner.signed = true;
self
}

/// Returns whether the iterator direction was reversed.
#[inline]
pub fn is_reversed(&self) -> bool {
self.inner.reversed
}

/// Returns whether the iterator treats keys as signed integers.
#[inline]
pub fn is_signed(&self) -> bool {
self.inner.signed
}
}

impl<'a> Iterator for RawKeys<'a> {
Expand Down Expand Up @@ -839,6 +875,18 @@ impl<'a> RawOwnedValues<'a> {
self.inner.signed = true;
self
}

/// Returns whether the iterator direction was reversed.
#[inline]
pub fn is_reversed(&self) -> bool {
self.inner.reversed
}

/// Returns whether the iterator treats keys as signed integers.
#[inline]
pub fn is_signed(&self) -> bool {
self.inner.signed
}
}

impl<'a> Iterator for RawOwnedValues<'a> {
Expand Down Expand Up @@ -934,6 +982,18 @@ impl<'a> RawValues<'a> {
self
}

/// Returns whether the iterator direction was reversed.
#[inline]
pub fn is_reversed(&self) -> bool {
self.reversed
}

/// Returns whether the iterator treats keys as signed integers.
#[inline]
pub fn is_signed(&self) -> bool {
self.signed
}

#[inline]
pub(crate) fn finish(&mut self, err: Error) -> Error {
self.status = IterStatus::Broken;
Expand Down
Loading

0 comments on commit ddcafea

Please sign in to comment.