From e86ed11799807a6016cec4e9ce9d3eab28e72061 Mon Sep 17 00:00:00 2001 From: Ivan Kalinin Date: Fri, 9 Aug 2024 20:37:27 +0200 Subject: [PATCH 1/2] refactor: unify range and slice naming --- fuzz/fuzz_targets/boc_decode.rs | 2 +- src/abi/contract.rs | 9 +- src/abi/value/de.rs | 18 +- src/abi/value/ser.rs | 114 ++++----- src/cell/builder.rs | 58 +++-- src/cell/mod.rs | 119 ++++++++- src/cell/slice.rs | 411 ++++++++++++++----------------- src/dict/aug.rs | 16 +- src/dict/mod.rs | 60 ++--- src/dict/ops/build.rs | 34 +-- src/dict/ops/find.rs | 28 +-- src/dict/ops/get.rs | 24 +- src/dict/ops/insert.rs | 42 ++-- src/dict/ops/remove.rs | 20 +- src/dict/ops/split_merge.rs | 4 +- src/dict/raw.rs | 53 ++-- src/dict/typed.rs | 4 +- src/merkle/proof.rs | 38 +-- src/merkle/update.rs | 21 +- src/models/account/mod.rs | 6 +- src/models/block/shard_hashes.rs | 8 +- src/models/currency.rs | 4 +- src/models/message/address.rs | 2 +- src/models/message/mod.rs | 48 ++-- src/models/mod.rs | 6 +- src/num/mod.rs | 12 +- src/num/varuint248.rs | 6 +- src/prelude.rs | 4 +- src/util.rs | 15 +- 29 files changed, 624 insertions(+), 562 deletions(-) diff --git a/fuzz/fuzz_targets/boc_decode.rs b/fuzz/fuzz_targets/boc_decode.rs index 5d6deb35..772ab6c9 100644 --- a/fuzz/fuzz_targets/boc_decode.rs +++ b/fuzz/fuzz_targets/boc_decode.rs @@ -12,7 +12,7 @@ fuzz_target!(|data: &[u8]| { _ = slice.get_u64(0); _ = slice.get_u128(0); _ = slice.get_u256(0); - if slice.try_advance(3, 0) { + if slice.skip_first(3, 0).is_ok() { _ = slice.get_u8(0); _ = slice.get_u16(0); _ = slice.get_u32(0); diff --git a/src/abi/contract.rs b/src/abi/contract.rs index ce9c1928..e9973036 100644 --- a/src/abi/contract.rs +++ b/src/abi/contract.rs @@ -10,8 +10,7 @@ use sha2::Digest; use crate::abi::value::ser::AbiSerializer; use crate::abi::AbiHeader; use crate::cell::{ - Cell, CellBuilder, CellFamily, CellSlice, CellSliceRange, CellSliceSize, DynCell, HashBytes, - Store, + Cell, CellBuilder, CellFamily, CellSlice, CellSliceRange, DynCell, HashBytes, Size, Store, }; use crate::dict::RawDict; use crate::models::{ @@ -494,7 +493,7 @@ impl Function { } else { // Skip signature if slice.load_bit()? { - slice.advance(512, 0)?; + slice.skip_first(512, 0)?; } // Skip headers ok!(AbiHeader::skip_all(&self.headers, slice)); @@ -732,7 +731,7 @@ impl<'f, 'a> ExternalInput<'f, 'a> { if reserve_signature { serializer.add_offset(if abi_version.major == 1 { // Reserve reference for signature - CellSliceSize { bits: 0, refs: 1 } + Size { bits: 0, refs: 1 } } else { let bits = if abi_version >= AbiVersion::V2_3 { // Reserve only for address as it also ensures the the signature will fit @@ -741,7 +740,7 @@ impl<'f, 'a> ExternalInput<'f, 'a> { // Reserve for `Some` non-empty signature 1 + 512 }; - CellSliceSize { bits, refs: 0 } + Size { bits, refs: 0 } }); } diff --git a/src/abi/value/de.rs b/src/abi/value/de.rs index cb8a3606..072a657c 100644 --- a/src/abi/value/de.rs +++ b/src/abi/value/de.rs @@ -264,17 +264,17 @@ impl AbiHeader { match ty { AbiHeaderType::Time => { ok!(preload_bits(64, slice)); - slice.advance(64, 0)?; + slice.skip_first(64, 0)?; } AbiHeaderType::Expire => { ok!(preload_bits(32, slice)); - slice.advance(32, 0)?; + slice.skip_first(32, 0)?; } AbiHeaderType::PublicKey => { ok!(preload_bits(1, slice)); if slice.load_bit()? { ok!(preload_bits(256, slice)); - slice.advance(256, 0)?; + slice.skip_first(256, 0)?; } } } @@ -315,7 +315,7 @@ fn preload_bits(bits: u16, slice: &mut CellSlice) -> Result<()> { return Ok(()); } - let remaining_bits = slice.remaining_bits(); + let remaining_bits = slice.size_bits(); if remaining_bits == 0 { let first_ref = slice.load_reference_as_slice()?; @@ -415,9 +415,9 @@ fn load_varuint_raw(size: NonZeroU8, slice: &mut CellSlice) -> Result> { } fn load_cell(version: AbiVersion, last: bool, slice: &mut CellSlice) -> Result { - if slice.remaining_refs() == 1 + if slice.size_refs() == 1 && (version.major == 1 && slice.cell().reference_count() as usize == MAX_REF_COUNT - || version.major > 1 && !last && slice.remaining_bits() == 0) + || version.major > 1 && !last && slice.size_bits() == 0) { *slice = slice.load_reference_as_slice()?; } @@ -796,7 +796,7 @@ mod tests { // 4 refs with empty cells let cell = Boc::decode_base64("te6ccgEBAgEACAAEAAEBAQEAAA==")?; let slice = &mut cell.as_slice()?; - slice.try_advance(0, 3); + slice.skip_first(0, 3)?; assert_basic_err!( AbiValue::load(&AbiType::Cell, AbiVersion::V1_0, slice), @@ -806,7 +806,7 @@ mod tests { // 3 refs with empty cells + last ref with a cell with 1 ref let cell = Boc::decode_base64("te6ccgEBAwEACwAEAAICAgEBAAIAAA==")?; let slice = &mut cell.as_slice()?; - slice.try_advance(0, 3); + slice.skip_first(0, 3)?; assert_eq!( AbiValue::load(&AbiType::Cell, AbiVersion::V1_0, slice)?, @@ -825,7 +825,7 @@ mod tests { // 4 refs with empty cells let cell = Boc::decode_base64("te6ccgEBAgEACAAEAAEBAQEAAA==")?; let slice = &mut cell.as_slice()?; - slice.try_advance(0, 3); + slice.skip_first(0, 3)?; assert_eq!( AbiValue::load(&AbiType::Cell, v, slice)?, diff --git a/src/abi/value/ser.rs b/src/abi/value/ser.rs index 0c25648d..59ceb981 100644 --- a/src/abi/value/ser.rs +++ b/src/abi/value/ser.rs @@ -8,7 +8,7 @@ use crate::abi::{ PlainAbiValue, }; use crate::cell::{ - Cell, CellBuilder, CellContext, CellSlice, CellSliceSize, CellTreeStats, Store, MAX_BIT_LEN, + Cell, CellBuilder, CellContext, CellSlice, CellTreeStats, Size, Store, MAX_BIT_LEN, MAX_REF_COUNT, }; use crate::dict::{self, RawDict}; @@ -110,44 +110,44 @@ impl AbiValue { } } - fn compute_exact_size_short(&self) -> CellSliceSize { - fn compute_varuint_size(n: &NonZeroU8, value: &BigUint) -> CellSliceSize { + fn compute_exact_size_short(&self) -> Size { + fn compute_varuint_size(n: &NonZeroU8, value: &BigUint) -> Size { let value_bytes: u8 = n.get() - 1; let len_bits = (8 - value_bytes.leading_zeros()) as u16; let value_bits = std::cmp::max(8, 8 * ((value.bits() + 7) / 8) as u16); - CellSliceSize { + Size { bits: len_bits + value_bits, refs: 0, } } match self { - Self::Uint(n, _) | Self::Int(n, _) => CellSliceSize { bits: *n, refs: 0 }, + Self::Uint(n, _) | Self::Int(n, _) => Size { bits: *n, refs: 0 }, Self::VarUint(n, value) => compute_varuint_size(n, value), Self::VarInt(n, value) => compute_varuint_size(n, value.magnitude()), - Self::Bool(_) => CellSliceSize { bits: 1, refs: 0 }, + Self::Bool(_) => Size { bits: 1, refs: 0 }, Self::Cell(_) | Self::Bytes(_) | Self::FixedBytes(_) | Self::String(_) - | Self::Ref(_) => CellSliceSize { bits: 0, refs: 1 }, - Self::Address(value) => CellSliceSize { + | Self::Ref(_) => Size { bits: 0, refs: 1 }, + Self::Address(value) => Size { bits: value.bit_len(), refs: 0, }, - Self::Token(tokens) => CellSliceSize { + Self::Token(tokens) => Size { bits: tokens.bit_len().unwrap_or(Tokens::MAX_BITS), refs: 0, }, - Self::Array(_, values) => CellSliceSize { + Self::Array(_, values) => Size { bits: 33, refs: !values.is_empty() as u8, }, - Self::FixedArray(_, values) => CellSliceSize { + Self::FixedArray(_, values) => Size { bits: 1, refs: !values.is_empty() as u8, }, - Self::Map(_, _, values) => CellSliceSize { + Self::Map(_, _, values) => Size { bits: 1, refs: !values.is_empty() as u8, }, @@ -157,16 +157,16 @@ impl AbiValue { if ty_size.bit_count < MAX_BIT_LEN as u64 && ty_size.cell_count < MAX_REF_COUNT as u64 { - CellSliceSize { bits: 1, refs: 0 } + value.compute_exact_size_short() + Size { bits: 1, refs: 0 } + value.compute_exact_size_short() } else { - CellSliceSize { bits: 1, refs: 1 } + Size { bits: 1, refs: 1 } } } else { - CellSliceSize { bits: 1, refs: 0 } + Size { bits: 1, refs: 0 } } } Self::Tuple(items) => { - let mut size = CellSliceSize::ZERO; + let mut size = Size::ZERO; for item in items { size = size.saturating_add(item.value.compute_exact_size_short()); } @@ -175,45 +175,45 @@ impl AbiValue { } } - fn compute_max_size_short(&self) -> CellSliceSize { + fn compute_max_size_short(&self) -> Size { match self { - Self::Uint(n, _) | Self::Int(n, _) => CellSliceSize { bits: *n, refs: 0 }, + Self::Uint(n, _) | Self::Int(n, _) => Size { bits: *n, refs: 0 }, Self::VarUint(n, _) | Self::VarInt(n, _) => { let value_bytes: u8 = n.get() - 1; let bits = (8 - value_bytes.leading_zeros()) as u16 + (value_bytes as u16 * 8); - CellSliceSize { bits, refs: 0 } + Size { bits, refs: 0 } } - Self::Bool(_) => CellSliceSize { bits: 1, refs: 0 }, + Self::Bool(_) => Size { bits: 1, refs: 0 }, Self::Cell(_) | Self::Bytes(_) | Self::FixedBytes(_) | Self::String(_) - | Self::Ref(_) => CellSliceSize { bits: 0, refs: 1 }, - Self::Address(_) => CellSliceSize { + | Self::Ref(_) => Size { bits: 0, refs: 1 }, + Self::Address(_) => Size { bits: IntAddr::BITS_MAX, refs: 0, }, - Self::Token(_) => CellSliceSize { + Self::Token(_) => Size { bits: Tokens::MAX_BITS, refs: 0, }, - Self::Array(..) => CellSliceSize { bits: 33, refs: 1 }, - Self::FixedArray(..) | Self::Map(..) => CellSliceSize { bits: 1, refs: 1 }, + Self::Array(..) => Size { bits: 33, refs: 1 }, + Self::FixedArray(..) | Self::Map(..) => Size { bits: 1, refs: 1 }, Self::Optional(ty, _) => { let ty_size = ty.max_size(); if ty_size.bit_count < MAX_BIT_LEN as u64 && ty_size.cell_count < MAX_REF_COUNT as u64 { - CellSliceSize { + Size { bits: 1 + ty_size.bit_count as u16, refs: ty_size.cell_count as u8, } } else { - CellSliceSize { bits: 1, refs: 1 } + Size { bits: 1, refs: 1 } } } Self::Tuple(items) => { - let mut size = CellSliceSize::ZERO; + let mut size = Size::ZERO; for item in items { size = size.saturating_add(item.value.compute_max_size_short()); } @@ -225,7 +225,7 @@ impl AbiValue { pub(crate) struct AbiSerializer { version: AbiVersion, - current: CellSliceSize, + current: Size, remaining_total: CellTreeStats, stack: Vec, } @@ -234,13 +234,13 @@ impl AbiSerializer { pub fn new(version: AbiVersion) -> Self { Self { version, - current: CellSliceSize::ZERO, + current: Size::ZERO, remaining_total: CellTreeStats::ZERO, stack: Vec::new(), } } - pub fn add_offset(&mut self, offset: CellSliceSize) { + pub fn add_offset(&mut self, offset: Size) { self.current += offset; } @@ -278,7 +278,7 @@ impl AbiSerializer { pub fn take_finalize(&mut self, context: &mut dyn CellContext) -> Result { debug_assert_eq!(self.remaining_total, CellTreeStats::ZERO); - self.current = CellSliceSize::ZERO; + self.current = Size::ZERO; self.remaining_total = CellTreeStats::ZERO; let mut result = self.stack.pop().unwrap_or_default(); @@ -293,14 +293,14 @@ impl AbiSerializer { Self::new(self.version) } - fn require_builder(&mut self, value_size: CellSliceSize) -> &mut CellBuilder { + fn require_builder(&mut self, value_size: Size) -> &mut CellBuilder { if self.stack.is_empty() { self.stack.push(CellBuilder::new()); } self.remaining_total -= value_size; - let remaining = CellSliceSize::MAX - self.current; + let remaining = Size::MAX - self.current; let store_inline = if value_size.bits > remaining.bits || value_size.refs > remaining.refs { false @@ -313,7 +313,7 @@ impl AbiSerializer { }; if !store_inline { - self.current = CellSliceSize::ZERO; + self.current = Size::ZERO; self.stack.push(CellBuilder::new()); } @@ -326,13 +326,13 @@ impl AbiSerializer { pub(crate) fn write_header_value(&mut self, value: &AbiHeader) -> Result<(), Error> { match value { AbiHeader::Time(value) => self - .require_builder(CellSliceSize { bits: 64, refs: 0 }) + .require_builder(Size { bits: 64, refs: 0 }) .store_u64(*value), AbiHeader::Expire(value) => self - .require_builder(CellSliceSize { bits: 32, refs: 0 }) + .require_builder(Size { bits: 32, refs: 0 }) .store_u32(*value), AbiHeader::PublicKey(value) => { - let target = self.require_builder(CellSliceSize { + let target = self.require_builder(Size { bits: 1 + if self.version.use_max_size() || value.is_some() { 256 } else { @@ -388,7 +388,7 @@ impl AbiSerializer { } fn write_int(&mut self, bits: u16, sign: Sign, value: &BigUint) -> Result<(), Error> { - let target = self.require_builder(CellSliceSize { bits, refs: 0 }); + let target = self.require_builder(Size { bits, refs: 0 }); write_int(bits, sign, value, target) } @@ -404,7 +404,7 @@ impl AbiSerializer { let len_bits = (8 - max_value_size.leading_zeros()) as u16; let value_bits = (bytes.len() * 8) as u16; - let target = self.require_builder(CellSliceSize { + let target = self.require_builder(Size { bits: if self.version.use_max_size() { len_bits + (max_value_size as u16) * 8 } else { @@ -418,17 +418,17 @@ impl AbiSerializer { } fn write_bool(&mut self, value: bool) -> Result<(), Error> { - let target = self.require_builder(CellSliceSize { bits: 1, refs: 0 }); + let target = self.require_builder(Size { bits: 1, refs: 0 }); target.store_bit(value) } fn write_cell(&mut self, cell: &Cell) -> Result<(), Error> { - let target = self.require_builder(CellSliceSize { bits: 0, refs: 1 }); + let target = self.require_builder(Size { bits: 0, refs: 1 }); target.store_reference(cell.clone()) } fn write_address(&mut self, address: &IntAddr) -> Result<(), Error> { - let target = self.require_builder(CellSliceSize { + let target = self.require_builder(Size { bits: if self.version.use_max_size() { IntAddr::BITS_MAX } else { @@ -440,7 +440,7 @@ impl AbiSerializer { } fn write_tokens(&mut self, tokens: &Tokens) -> Result<(), Error> { - let target = self.require_builder(CellSliceSize { + let target = self.require_builder(Size { bits: if self.version.use_max_size() { Tokens::MAX_BITS } else { @@ -470,7 +470,7 @@ impl AbiSerializer { let (head, tail) = data.split_at(len); data = head; - if result.bit_len() > 0 { + if result.size_bits() > 0 { let child = ok!(std::mem::take(&mut result).build_ext(context)); ok!(result.store_reference(child)); } @@ -480,7 +480,7 @@ impl AbiSerializer { bytes_per_builder = std::cmp::min(MAX_BYTES_PER_BUILDER, len); } - let target = self.require_builder(CellSliceSize { bits: 0, refs: 1 }); + let target = self.require_builder(Size { bits: 0, refs: 1 }); target.store_reference(ok!(result.build())) } @@ -522,7 +522,7 @@ impl AbiSerializer { !values.is_empty() as u8 }; - let target = self.require_builder(CellSliceSize { bits, refs }); + let target = self.require_builder(Size { bits, refs }); if !fixed_len { ok!(target.store_u32(values.len() as u32)); @@ -566,10 +566,10 @@ impl AbiSerializer { context, )); - ok!(key_builder.rewind(key_builder.bit_len())); + ok!(key_builder.rewind(key_builder.size_bits())); } - let target = self.require_builder(CellSliceSize { bits: 1, refs: 1 }); + let target = self.require_builder(Size { bits: 1, refs: 1 }); dict.store_into(target, context) } @@ -582,13 +582,13 @@ impl AbiSerializer { let (max_size, inline) = { let ty_size = ty.max_size(); if ty_size.bit_count < MAX_BIT_LEN as _ && ty_size.cell_count < MAX_REF_COUNT as _ { - let size = CellSliceSize { + let size = Size { bits: 1 + ty_size.bit_count as u16, refs: ty_size.cell_count as u8, }; (size, true) } else { - (CellSliceSize { bits: 1, refs: 1 }, false) + (Size { bits: 1, refs: 1 }, false) } }; @@ -604,12 +604,12 @@ impl AbiSerializer { let target = self.require_builder(if self.version.use_max_size() { max_size } else if inline { - CellSliceSize { - bits: 1 + value.bit_len(), - refs: value.reference_count(), + Size { + bits: 1 + value.size_bits(), + refs: value.size_refs(), } } else { - CellSliceSize { bits: 1, refs: 1 } + Size { bits: 1, refs: 1 } }); ok!(target.store_bit(true)); @@ -623,7 +623,7 @@ impl AbiSerializer { let target = self.require_builder(if self.version.use_max_size() { max_size } else { - CellSliceSize { bits: 1, refs: 0 } + Size { bits: 1, refs: 0 } }); target.store_bit(false) } @@ -638,7 +638,7 @@ impl AbiSerializer { let builder = ok!(serializer.finalize(context)); ok!(builder.build_ext(context)) }; - let target = self.require_builder(CellSliceSize { bits: 0, refs: 1 }); + let target = self.require_builder(Size { bits: 0, refs: 1 }); target.store_reference(cell) } } diff --git a/src/cell/builder.rs b/src/cell/builder.rs index 52d69955..a4d4688f 100644 --- a/src/cell/builder.rs +++ b/src/cell/builder.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use crate::cell::cell_context::{CellContext, CellParts}; use crate::cell::{ Cell, CellDescriptor, CellImpl, CellInner, CellSlice, CellType, DynCell, HashBytes, LevelMask, - MAX_BIT_LEN, MAX_REF_COUNT, + Size, MAX_BIT_LEN, MAX_REF_COUNT, }; use crate::error::Error; use crate::util::{ArrayVec, Bitstring}; @@ -318,12 +318,12 @@ impl CellBuilder { } /// Creates an empty cell builder. - pub fn new() -> Self { + pub const fn new() -> Self { Self { data: [0; 128], bit_len: 0, is_exotic: false, - references: Default::default(), + references: ArrayVec::new(), } } @@ -354,43 +354,59 @@ impl CellBuilder { /// Returns an underlying cell data. #[inline] - pub fn raw_data(&self) -> &[u8; 128] { + pub const fn raw_data(&self) -> &[u8; 128] { &self.data } + /// Returns the stored cell size. + pub const fn size(&self) -> Size { + Size { + bits: self.bit_len, + refs: self.references.len() as u8, + } + } + /// Returns the data size of this cell in bits. #[inline] - pub fn bit_len(&self) -> u16 { + pub const fn size_bits(&self) -> u16 { self.bit_len } /// Returns child cell count. #[inline(always)] - pub const fn reference_count(&self) -> u8 { + pub const fn size_refs(&self) -> u8 { self.references.len() as u8 } + /// Returns the remaining capacity in bits and references. + pub const fn spare_capacity(&self) -> Size { + Size { + bits: self.spare_capacity_bits(), + refs: self.spare_capacity_refs(), + } + } + /// Returns remaining data capacity in bits. #[inline] - pub fn spare_bits_capacity(&self) -> u16 { + pub const fn spare_capacity_bits(&self) -> u16 { MAX_BIT_LEN - self.bit_len } /// Returns remaining references capacity. #[inline] - pub fn spare_refs_capacity(&self) -> u8 { + pub const fn spare_capacity_refs(&self) -> u8 { (MAX_REF_COUNT - self.references.len()) as u8 } /// Returns true if there is enough remaining capacity to fit `bits` and `refs`. #[inline] - pub fn has_capacity(&self, bits: u16, refs: u8) -> bool { + pub const fn has_capacity(&self, bits: u16, refs: u8) -> bool { self.bit_len + bits <= MAX_BIT_LEN && self.references.len() + refs as usize <= MAX_REF_COUNT } /// Returns whether this cell will be built as an exotic. #[inline] - pub fn is_exotic(&self) -> bool { + pub const fn is_exotic(&self) -> bool { self.is_exotic } @@ -727,7 +743,7 @@ impl CellBuilder { builder: &mut CellBuilder, value: &CellSlice<'_>, ) -> Result<(), Error> { - let bits = value.remaining_bits(); + let bits = value.size_bits(); if builder.bit_len + bits <= MAX_BIT_LEN { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. let mut slice_data = @@ -905,8 +921,8 @@ impl CellBuilder { T: AsRef>, { fn store_slice_impl(builder: &mut CellBuilder, value: &CellSlice<'_>) -> Result<(), Error> { - if builder.bit_len + value.remaining_bits() <= MAX_BIT_LEN - && builder.references.len() + value.remaining_refs() as usize <= MAX_REF_COUNT + if builder.bit_len + value.size_bits() <= MAX_BIT_LEN + && builder.references.len() + value.size_refs() as usize <= MAX_REF_COUNT { ok!(builder.store_slice_data(value)); for cell in value.references().cloned() { @@ -1273,15 +1289,15 @@ mod tests { fn rewind_builder() { let mut builder = CellBuilder::new(); builder.store_u32(0xdeafbeaf).unwrap(); - assert_eq!(builder.bit_len(), 32); + assert_eq!(builder.size_bits(), 32); assert_eq!(builder.data[..4], 0xdeafbeaf_u32.to_be_bytes()); builder.rewind(5).unwrap(); - assert_eq!(builder.bit_len(), 27); + assert_eq!(builder.size_bits(), 27); assert_eq!(builder.data[..4], 0xdeafbea0_u32.to_be_bytes()); builder.store_u32(0xdeafbeaf).unwrap(); - assert_eq!(builder.bit_len(), 32 + 27); + assert_eq!(builder.size_bits(), 32 + 27); assert_eq!( builder.data[..8], [0xde, 0xaf, 0xbe, 0xbb, 0xd5, 0xf7, 0xd5, 0xe0] @@ -1295,23 +1311,23 @@ mod tests { assert_eq!(builder.rewind(32), Err(Error::CellUnderflow)); builder.rewind(27).unwrap(); - assert_eq!(builder.bit_len(), 0); + assert_eq!(builder.size_bits(), 0); assert_eq!(builder.data, [0u8; 128]); builder.store_raw(&[0xff; 128], MAX_BIT_LEN).unwrap(); - assert_eq!(builder.bit_len(), MAX_BIT_LEN); + assert_eq!(builder.size_bits(), MAX_BIT_LEN); let mut target = [0xff; 128]; target[127] = 0xfe; assert_eq!(builder.data, target); builder.rewind(3).unwrap(); - assert_eq!(builder.bit_len(), MAX_BIT_LEN - 3); + assert_eq!(builder.size_bits(), MAX_BIT_LEN - 3); target[127] = 0xf0; assert_eq!(builder.data, target); builder.rewind(8).unwrap(); - assert_eq!(builder.bit_len(), MAX_BIT_LEN - 3 - 8); + assert_eq!(builder.size_bits(), MAX_BIT_LEN - 3 - 8); target[126] = 0xf0; target[127] = 0x00; assert_eq!(builder.data, target); @@ -1356,7 +1372,7 @@ mod tests { let mut builder = CellBuilder::new(); let mut slice = cell.as_slice()?; - assert!(slice.try_advance(3, 0)); + slice.skip_first(3, 0)?; builder.store_slice(slice)?; let cell = builder.build()?; println!("{}", cell.display_tree()); diff --git a/src/cell/mod.rs b/src/cell/mod.rs index 02bc25ad..3f1a1ab7 100644 --- a/src/cell/mod.rs +++ b/src/cell/mod.rs @@ -9,7 +9,7 @@ use crate::util::Bitstring; pub use self::builder::{CellBuilder, CellRefsBuilder, Store}; pub use self::cell_context::{CellContext, CellParts, LoadMode}; pub use self::cell_impl::{StaticCell, VirtualCellWrapper}; -pub use self::slice::{CellSlice, CellSliceParts, CellSliceRange, CellSliceSize, ExactSize, Load}; +pub use self::slice::{CellSlice, CellSliceParts, CellSliceRange, ExactSize, Load}; pub use self::usage_tree::{UsageTree, UsageTreeMode, UsageTreeWithSubtrees}; #[cfg(not(feature = "sync"))] @@ -1244,6 +1244,109 @@ impl Iterator for LevelMaskIter { } } +/// A size of a cell. +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +pub struct Size { + /// Total number of bits in cell slice. + pub bits: u16, + /// Total number refs in cell slice. + pub refs: u8, +} + +impl Size { + /// The additive identity for this type, i.e. `0`. + pub const ZERO: Self = Self { bits: 0, refs: 0 }; + + /// The multiplicative bits identity for this type, i.e. `1 bit`. + pub const BIT: Self = Self { bits: 1, refs: 0 }; + + /// The multiplicative refs identity for this type, i.e. `1 ref`. + pub const REF: Self = Self { bits: 0, refs: 1 }; + + /// The largest valid value that can be represented by this type. + pub const MAX: Self = Self { + bits: MAX_BIT_LEN, + refs: MAX_REF_COUNT as _, + }; + + /// Returns true if the number of bits and refs is in the valid range for the cell. + #[inline] + pub const fn fits_into_cell(&self) -> bool { + self.bits <= MAX_BIT_LEN && self.refs <= MAX_REF_COUNT as _ + } + + /// Saturating size addition. Computes self + rhs for bits and refs, + /// saturating at the numeric bounds instead of overflowing. + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + Self { + bits: self.bits.saturating_add(rhs.bits), + refs: self.refs.saturating_add(rhs.refs), + } + } + + /// Saturating size substraction. Computes self - rhs for bits and refs, + /// saturating at the numeric bounds instead of overflowing. + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + Self { + bits: self.bits.saturating_sub(rhs.bits), + refs: self.refs.saturating_sub(rhs.refs), + } + } + + /// Returns true if there are no bits and refs. + pub const fn is_zero(self) -> bool { + self.bits == 0 && self.refs == 0 + } +} + +impl From for CellTreeStats { + #[inline] + fn from(value: Size) -> Self { + Self { + bit_count: value.bits as _, + cell_count: value.refs as _, + } + } +} + +impl std::ops::Add for Size { + type Output = Self; + + #[inline] + fn add(mut self, rhs: Self) -> Self::Output { + self += rhs; + self + } +} + +impl std::ops::AddAssign for Size { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.bits += rhs.bits; + self.refs += rhs.refs; + } +} + +impl std::ops::Sub for Size { + type Output = Self; + + #[inline] + fn sub(mut self, rhs: Self) -> Self::Output { + self -= rhs; + self + } +} + +impl std::ops::SubAssign for Size { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + self.bits -= rhs.bits; + self.refs -= rhs.refs; + } +} + /// Cell tree storage stats. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub struct CellTreeStats { @@ -1281,11 +1384,11 @@ impl std::ops::AddAssign for CellTreeStats { } } -impl std::ops::Add for CellTreeStats { +impl std::ops::Add for CellTreeStats { type Output = Self; #[inline] - fn add(self, rhs: CellSliceSize) -> Self::Output { + fn add(self, rhs: Size) -> Self::Output { Self { bit_count: self.bit_count.saturating_add(rhs.bits as _), cell_count: self.cell_count.saturating_add(rhs.refs as _), @@ -1304,8 +1407,8 @@ impl std::iter::Sum for CellTreeStats { } } -impl std::ops::AddAssign for CellTreeStats { - fn add_assign(&mut self, rhs: CellSliceSize) { +impl std::ops::AddAssign for CellTreeStats { + fn add_assign(&mut self, rhs: Size) { self.bit_count = self.bit_count.saturating_add(rhs.bits as _); self.cell_count = self.cell_count.saturating_add(rhs.refs as _); } @@ -1329,9 +1432,9 @@ impl std::ops::SubAssign for CellTreeStats { } } -impl std::ops::SubAssign for CellTreeStats { +impl std::ops::SubAssign for CellTreeStats { #[inline] - fn sub_assign(&mut self, rhs: CellSliceSize) { + fn sub_assign(&mut self, rhs: Size) { self.bit_count = self.bit_count.saturating_sub(rhs.bits as _); self.cell_count = self.cell_count.saturating_sub(rhs.refs as _); } @@ -1419,7 +1522,7 @@ impl<'a> StorageStat<'a> { /// /// Returns `false` if the limit was reached. pub fn add_slice(&mut self, slice: &CellSlice<'a>) -> bool { - self.stats.bit_count += slice.remaining_bits() as u64; + self.stats.bit_count += slice.size_bits() as u64; self.stack.clear(); self.stack.push(slice.references()); diff --git a/src/cell/slice.rs b/src/cell/slice.rs index b8bd23b3..f72eb617 100644 --- a/src/cell/slice.rs +++ b/src/cell/slice.rs @@ -3,8 +3,7 @@ use std::rc::Rc; use std::sync::Arc; use crate::cell::{ - Cell, CellTreeStats, CellType, DynCell, HashBytes, LevelMask, RefsIter, StorageStat, - MAX_BIT_LEN, MAX_REF_COUNT, + Cell, CellTreeStats, CellType, DynCell, HashBytes, LevelMask, RefsIter, Size, StorageStat, }; use crate::error::Error; use crate::util::{unlikely, Bitstring}; @@ -88,8 +87,8 @@ impl<'a, T: Load<'a>> Load<'a> for Option { impl ExactSize for Option { #[inline] - fn exact_size(&self) -> CellSliceSize { - let mut total = CellSliceSize { bits: 1, refs: 0 }; + fn exact_size(&self) -> Size { + let mut total = Size { bits: 1, refs: 0 }; if let Some(this) = self { total += this.exact_size(); } @@ -168,8 +167,8 @@ impl<'a> Load<'a> for &'a DynCell { impl ExactSize for DynCell { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { bits: 0, refs: 1 } + fn exact_size(&self) -> Size { + Size { bits: 0, refs: 1 } } } @@ -181,8 +180,8 @@ impl<'a> Load<'a> for Cell { impl ExactSize for Cell { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { bits: 0, refs: 1 } + fn exact_size(&self) -> Size { + Size { bits: 0, refs: 1 } } } @@ -191,8 +190,8 @@ pub type CellSliceParts = (Cell, CellSliceRange); impl ExactSize for CellSliceParts { #[inline] - fn exact_size(&self) -> CellSliceSize { - self.1.exact_size_const() + fn exact_size(&self) -> Size { + self.1.size() } } @@ -265,7 +264,7 @@ impl CellSliceRange { /// The following must be true: /// - cell is not pruned /// - range is in cell bounds - pub unsafe fn apply_unchecked(self, cell: &T) -> CellSlice<'_> + pub fn apply_allow_special(self, cell: &T) -> CellSlice<'_> where T: AsRef + ?Sized, { @@ -276,15 +275,15 @@ impl CellSliceRange { } /// Returns the number of remaining bits and refs in the slice. - pub const fn exact_size_const(&self) -> CellSliceSize { - CellSliceSize { - bits: self.remaining_bits(), - refs: self.remaining_refs(), + pub const fn size(&self) -> Size { + Size { + bits: self.size_bits(), + refs: self.size_refs(), } } /// Returns the number of remaining bits of data in the slice. - pub const fn remaining_bits(&self) -> u16 { + pub const fn size_bits(&self) -> u16 { if self.bits_start > self.bits_end { 0 } else { @@ -293,7 +292,7 @@ impl CellSliceRange { } /// Returns the number of remaining references in the slice. - pub const fn remaining_refs(&self) -> u8 { + pub const fn size_refs(&self) -> u8 { if self.refs_start > self.refs_end { 0 } else { @@ -301,6 +300,11 @@ impl CellSliceRange { } } + /// Returns whether there are no data bits and refs left. + pub const fn is_empty(&self) -> bool { + self.is_data_empty() && self.is_refs_empty() + } + /// Returns whether there are no bits of data left. pub const fn is_data_empty(&self) -> bool { self.bits_start >= self.bits_end @@ -311,13 +315,21 @@ impl CellSliceRange { self.refs_start >= self.refs_end } + /// Returns the start of data and reference windows. + pub const fn offset(&self) -> Size { + Size { + bits: self.bits_start, + refs: self.refs_start, + } + } + /// Returns the start of the data window. - pub const fn bits_offset(&self) -> u16 { + pub const fn offset_bits(&self) -> u16 { self.bits_start } /// Returns the start of the references window. - pub const fn refs_offset(&self) -> u8 { + pub const fn offset_refs(&self) -> u8 { self.refs_start } @@ -326,25 +338,56 @@ impl CellSliceRange { self.bits_start + bits <= self.bits_end && self.refs_start + refs <= self.refs_end } - /// Tries to advance the start of data and refs windows, - /// returns `false` if `bits` or `refs` are greater than the remainder. - pub fn try_advance(&mut self, bits: u16, refs: u8) -> bool { - if self.bits_start + bits <= self.bits_end && self.refs_start + refs <= self.refs_end { - self.bits_start += bits; - self.refs_start += refs; - true - } else { - false + /// Tries to advance the start of data and refs windows. + pub fn skip_first(&mut self, bits: u16, refs: u8) -> Result<(), Error> { + if unlikely( + self.bits_start + bits > self.bits_end || self.refs_start + refs > self.refs_end, + ) { + return Err(Error::CellUnderflow); } + + self.bits_start += bits; + self.refs_start += refs; + Ok(()) } - /// Tries to advance the start of data and refs windows. - pub fn advance(&mut self, bits: u16, refs: u8) -> Result<(), Error> { - if self.try_advance(bits, refs) { - Ok(()) - } else { - Err(Error::CellUnderflow) + /// Leaves only the first `bits` and `refs` in the slice. + pub fn only_first(&mut self, bits: u16, refs: u8) -> Result<(), Error> { + if unlikely( + self.bits_start + bits > self.bits_end || self.refs_start + refs > self.refs_end, + ) { + return Err(Error::CellUnderflow); + } + + self.bits_end = self.bits_start + bits; + self.refs_end = self.refs_start + refs; + Ok(()) + } + + /// Removes the last `bits` and `refs` from the slice. + pub fn skip_last(&mut self, bits: u16, refs: u8) -> Result<(), Error> { + if unlikely( + self.bits_start + bits > self.bits_end || self.refs_start + refs > self.refs_end, + ) { + return Err(Error::CellUnderflow); + } + + self.bits_end -= bits; + self.refs_end -= refs; + Ok(()) + } + + /// Leaves only the last `bits` and `refs` in the slice. + pub fn only_last(&mut self, bits: u16, refs: u8) -> Result<(), Error> { + if unlikely( + self.bits_start + bits > self.bits_end || self.refs_start + refs > self.refs_end, + ) { + return Err(Error::CellUnderflow); } + + self.bits_start = self.bits_end - bits; + self.refs_start = self.refs_end - refs; + Ok(()) } /// Returns a slice range starting at the same bits and refs offsets, @@ -455,6 +498,11 @@ impl<'a> CellSlice<'a> { self.cell.level_mask() } + /// Returns whether there are no data bits and refs left. + pub const fn is_empty(&self) -> bool { + self.range.is_empty() + } + /// Returns whether there are no bits of data left. /// /// # Examples @@ -504,18 +552,23 @@ impl<'a> CellSlice<'a> { } /// Returns the number of remaining bits and refs in the slice. - pub const fn exact_size_const(&self) -> CellSliceSize { - self.range.exact_size_const() + pub const fn size(&self) -> Size { + self.range.size() } /// Returns the number of remaining bits of data in the slice. - pub const fn remaining_bits(&self) -> u16 { - self.range.remaining_bits() + pub const fn size_bits(&self) -> u16 { + self.range.size_bits() } /// Returns the number of remaining references in the slice. - pub const fn remaining_refs(&self) -> u8 { - self.range.remaining_refs() + pub const fn size_refs(&self) -> u8 { + self.range.size_refs() + } + + /// Returns the start of data and reference windows. + pub const fn offset(&self) -> Size { + self.range.offset() } /// Returns the start of the data window. @@ -532,12 +585,12 @@ impl<'a> CellSlice<'a> { /// }; /// let mut slice = cell.as_slice()?; /// slice.load_u8()?; - /// assert_eq!(slice.bits_offset(), 8); + /// assert_eq!(slice.offset_bits(), 8); /// # Ok(()) } /// ``` #[inline] - pub const fn bits_offset(&self) -> u16 { - self.range.bits_offset() + pub const fn offset_bits(&self) -> u16 { + self.range.offset_bits() } /// Returns the start of the references window. @@ -555,12 +608,12 @@ impl<'a> CellSlice<'a> { /// let mut slice = cell.as_slice()?; /// /// slice.load_reference()?; - /// assert_eq!(slice.refs_offset(), 1); + /// assert_eq!(slice.offset_refs(), 1); /// # Ok(()) } /// ``` #[inline] - pub const fn refs_offset(&self) -> u8 { - self.range.refs_offset() + pub const fn offset_refs(&self) -> u8 { + self.range.offset_refs() } /// Returns true if the slice contains at least `bits` and `refs`. @@ -605,74 +658,89 @@ impl<'a> CellSlice<'a> { StorageStat::compute_for_slice(self, limit) } - /// Tries to advance the start of data and refs windows, - /// returns `false` if `bits` or `refs` are greater than the remainder. - pub fn try_advance(&mut self, bits: u16, refs: u8) -> bool { - self.range.try_advance(bits, refs) - } - /// Tries to advance the start of data and refs windows. - pub fn advance(&mut self, bits: u16, refs: u8) -> Result<(), Error> { - self.range.advance(bits, refs) + pub fn skip_first(&mut self, bits: u16, refs: u8) -> Result<(), Error> { + self.range.skip_first(bits, refs) } - /// Compares two slices by their data window **content** and refs. - /// - /// NOTE: this method is quite computationally heavy as it compares the content - /// of two potentially unaligned slices. Use it with caution or check by cell. - pub fn cmp_by_content(&self, b: &CellSlice) -> Result { - let a = self; + /// Leaves only the first `bits` and `refs` in the slice. + pub fn only_first(&mut self, bits: u16, refs: u8) -> Result<(), Error> { + self.range.only_first(bits, refs) + } - // Fast check - if a.cell == b.cell - && a.bits_offset() == b.bits_offset() - && a.refs_offset() == b.refs_offset() - { - return Ok((a.remaining_bits(), a.remaining_refs()) - .cmp(&(b.remaining_bits(), b.remaining_refs()))); - } + /// Removes the last `bits` and `refs` from the slice. + pub fn skip_last(&mut self, bits: u16, refs: u8) -> Result<(), Error> { + self.range.skip_last(bits, refs) + } - // Slow path - self.cmp_by_content_only(b) + /// Leaves only the last `bits` and `refs` in the slice. + pub fn only_last(&mut self, bits: u16, refs: u8) -> Result<(), Error> { + self.range.only_last(bits, refs) } - pub(crate) fn cmp_by_content_only(&self, b: &CellSlice) -> Result { + /// Lexicographically compares slice data. + /// + /// NOTE: this method is quite computationally heavy as it compares the content + /// of two potentially unaligned slices. Use it with caution or check by cell. + pub fn lex_cmp(&self, rhs: &CellSlice) -> Result { use std::cmp::Ordering; - let a = self; + let lhs = self; + let lhs_bits = lhs.size_bits(); + let rhs_bits = rhs.size_bits(); - // Slow path - match (a.remaining_bits(), a.remaining_refs()) - .cmp(&(b.remaining_bits(), b.remaining_refs())) - { - Ordering::Equal => {} - ord => return Ok(ord), - }; + // Fast check + + // NOTE: We can ignore pointer metadata since we are comparing only bits, + // and custom implementations of `CellImpl` do not alter data behavior. + if std::ptr::addr_eq(lhs.cell, rhs.cell) && lhs.offset_bits() == rhs.offset_bits() { + return Ok(lhs_bits.cmp(&rhs_bits)); + } - let bits = a.remaining_bits(); + // Full check + let bits = std::cmp::min(lhs_bits, rhs_bits); let rem = bits % 32; for offset in (0..bits - rem).step_by(32) { - match ok!(a.get_u32(offset)).cmp(&ok!(b.get_u32(offset))) { + match ok!(lhs.get_u32(offset)).cmp(&ok!(rhs.get_u32(offset))) { Ordering::Equal => {} ord => return Ok(ord), } } if rem > 0 { - match ok!(a.get_uint(bits - rem, rem)).cmp(&ok!(b.get_uint(bits - rem, rem))) { + match ok!(lhs.get_uint(bits - rem, rem)).cmp(&ok!(rhs.get_uint(bits - rem, rem))) { Ordering::Equal => {} ord => return Ok(ord), } } - for (a, b) in self.references().zip(b.references()) { - match a.repr_hash().cmp(b.repr_hash()) { - Ordering::Equal => {} - ord => return Ok(ord), + Ok(lhs_bits.cmp(&rhs_bits)) + } + + /// Returns `true` if two slices have the same data bits and refs. + /// + /// NOTE: this method is quite computationally heavy as it compares the content + /// of two potentially unaligned slices. Use it with caution or check by cell. + pub fn contents_eq(&self, rhs: &CellSlice) -> Result { + let lhs = self; + + // Fast check + if lhs.size_bits() != rhs.size_bits() || lhs.size_refs() != rhs.size_refs() { + return Ok(false); + } + + // Full check + if ok!(self.lex_cmp(rhs)).is_ne() { + return Ok(false); + } + + for (lhs, rhs) in self.references().zip(rhs.references()) { + if lhs.repr_hash() != rhs.repr_hash() { + return Ok(false); } } - Ok(Ordering::Equal) + Ok(true) } /// Returns a slice starting at the same bits and refs offsets, @@ -684,18 +752,6 @@ impl<'a> CellSlice<'a> { } } - /// Shrinks the slice down to a prefix of the specified length. - pub fn shrink(&mut self, bits: Option, refs: Option) -> Result<(), Error> { - let bits = bits.unwrap_or_else(|| self.remaining_bits()); - let refs = refs.unwrap_or_else(|| self.remaining_refs()); - if self.has_remaining(bits, refs) { - *self = self.get_prefix(bits, refs); - Ok(()) - } else { - Err(Error::CellUnderflow) - } - } - /// Returns a subslice with the data prefix removed. /// /// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. @@ -726,15 +782,15 @@ impl<'a> CellSlice<'a> { /// # Ok(()) } /// ``` pub fn strip_data_prefix<'b>(&self, prefix: &CellSlice<'b>) -> Option> { - let prefix_len = prefix.remaining_bits(); + let prefix_len = prefix.size_bits(); if prefix_len == 0 { Some(*self) - } else if self.remaining_bits() < prefix_len { + } else if self.size_bits() < prefix_len { None } else { let mut result = *self; let lcp = self.longest_common_data_prefix_impl(prefix, prefix_len); - if prefix_len <= lcp && result.try_advance(prefix_len, 0) { + if prefix_len <= lcp && result.skip_first(prefix_len, 0).is_ok() { Some(result) } else { None @@ -766,7 +822,7 @@ impl<'a> CellSlice<'a> { /// /// let lcp = slice.longest_common_data_prefix(&prefix.as_slice()?); /// assert_eq!(lcp.get_u16(0)?, 0xdead); - /// assert_eq!(lcp.remaining_bits(), 16); + /// assert_eq!(lcp.size_bits(), 16); /// # Ok(()) } /// ``` pub fn longest_common_data_prefix(&self, other: &Self) -> Self { @@ -1542,7 +1598,7 @@ impl<'a> CellSlice<'a> { s: &'b CellSlice<'a>, bytes: &'b mut [u8; 128], ) -> Result, std::fmt::Error> { - let bit_len = s.remaining_bits(); + let bit_len = s.size_bits(); if s.get_raw(0, bytes, bit_len).is_err() { return Err(std::fmt::Error); } @@ -1571,56 +1627,56 @@ impl<'a> CellSlice<'a> { impl ExactSize for CellSlice<'_> { #[inline] - fn exact_size(&self) -> CellSliceSize { - self.exact_size_const() + fn exact_size(&self) -> Size { + self.size() } } /// A type with a known size in bits and refs. pub trait ExactSize { /// Exact size of the value when it is stored in a slice. - fn exact_size(&self) -> CellSliceSize; + fn exact_size(&self) -> Size; } impl ExactSize for &T { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { T::exact_size(self) } } impl ExactSize for &mut T { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { T::exact_size(self) } } impl ExactSize for Box { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { T::exact_size(self) } } impl ExactSize for Arc { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { T::exact_size(self) } } impl ExactSize for Rc { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { T::exact_size(self) } } impl ExactSize for () { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize::ZERO + fn exact_size(&self) -> Size { + Size::ZERO } } @@ -1633,7 +1689,7 @@ macro_rules! strip_plus { macro_rules! impl_exact_size_for_tuples { ($( ($($tt:tt: $t:ident),+) ),*$(,)?) => {$( impl<$($t: ExactSize),+> ExactSize for ($($t),*,) { - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { strip_plus!($(+ ExactSize::exact_size(&self.$tt))+) } } @@ -1649,98 +1705,6 @@ impl_exact_size_for_tuples! { (0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5), } -/// A size of a cell slice. -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] -pub struct CellSliceSize { - /// Total number of bits in cell slice. - pub bits: u16, - /// Total number refs in cell slice. - pub refs: u8, -} - -impl CellSliceSize { - /// The additive identity for this type, i.e. `0`. - pub const ZERO: Self = Self { bits: 0, refs: 0 }; - - /// The largest valid value that can be represented by this type. - pub const MAX: Self = Self { - bits: MAX_BIT_LEN, - refs: MAX_REF_COUNT as _, - }; - - /// Returns true if the number of bits and refs is in the valid range for the cell. - #[inline] - pub const fn fits_into_cell(&self) -> bool { - self.bits <= MAX_BIT_LEN && self.refs <= MAX_REF_COUNT as _ - } - - /// Saturating size addition. Computes self + rhs for bits and refs, - /// saturating at the numeric bounds instead of overflowing. - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - Self { - bits: self.bits.saturating_add(rhs.bits), - refs: self.refs.saturating_add(rhs.refs), - } - } - - /// Saturating size substraction. Computes self - rhs for bits and refs, - /// saturating at the numeric bounds instead of overflowing. - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - Self { - bits: self.bits.saturating_sub(rhs.bits), - refs: self.refs.saturating_sub(rhs.refs), - } - } -} - -impl From for CellTreeStats { - #[inline] - fn from(value: CellSliceSize) -> Self { - Self { - bit_count: value.bits as _, - cell_count: value.refs as _, - } - } -} - -impl std::ops::Add for CellSliceSize { - type Output = Self; - - #[inline] - fn add(mut self, rhs: Self) -> Self::Output { - self += rhs; - self - } -} - -impl std::ops::AddAssign for CellSliceSize { - #[inline] - fn add_assign(&mut self, rhs: Self) { - self.bits += rhs.bits; - self.refs += rhs.refs; - } -} - -impl std::ops::Sub for CellSliceSize { - type Output = Self; - - #[inline] - fn sub(mut self, rhs: Self) -> Self::Output { - self -= rhs; - self - } -} - -impl std::ops::SubAssign for CellSliceSize { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - self.bits -= rhs.bits; - self.refs -= rhs.refs; - } -} - #[cfg(test)] mod tests { use crate::error::Error; @@ -1792,7 +1756,7 @@ mod tests { b.store_u16(0xffff) }); let mut slice1 = cell1.as_slice()?; - slice1.try_advance(4, 0); + slice1.skip_first(4, 0)?; let cell2 = build_cell(|b| { b.store_uint(0xbcd, 12)?; @@ -1816,11 +1780,11 @@ mod tests { fn longest_common_data_prefix() -> anyhow::Result<()> { let cell1 = build_cell(|b| b.store_u64(0xffffffff00000000)); let mut slice1 = cell1.as_slice()?; - slice1.try_advance(1, 0); + slice1.skip_first(1, 0)?; let cell2 = build_cell(|b| b.store_u64(0xfffffff000000000)); let mut slice2 = cell2.as_slice()?; - slice2.try_advance(6, 0); + slice2.skip_first(6, 0)?; let prefix = slice1.longest_common_data_prefix(&slice2); @@ -1835,32 +1799,32 @@ mod tests { let prefix = cell1 .as_slice()? .longest_common_data_prefix(&cell2.as_slice()?); - assert_eq!(prefix.remaining_bits(), 31); + assert_eq!(prefix.size_bits(), 31); // let cell1 = build_cell(|b| b.store_raw(&[0, 0, 2, 2], 32)); let mut slice1 = cell1.as_slice()?; - slice1.try_advance(23, 0); + slice1.skip_first(23, 0)?; let cell2 = build_cell(|b| b.store_raw(&[0; 128], 1023)); let slice2 = cell2.as_slice()?.get_prefix(8, 0); let prefix = slice1.longest_common_data_prefix(&slice2); - assert_eq!(prefix.remaining_bits(), 7); + assert_eq!(prefix.size_bits(), 7); // let cell1 = build_cell(|b| b.store_u16(0)); let mut slice1 = cell1.as_slice()?; - slice1.try_advance(5, 0); + slice1.skip_first(5, 0)?; let cell2 = build_cell(|b| b.store_u8(0)); let mut slice2 = cell2.as_slice()?; - slice2.try_advance(2, 0); + slice2.skip_first(2, 0)?; let prefix = slice1 .get_prefix(5, 0) .longest_common_data_prefix(&slice2.get_prefix(5, 0)); - assert_eq!(prefix.remaining_bits(), 5); + assert_eq!(prefix.size_bits(), 5); Ok(()) } @@ -1872,21 +1836,18 @@ mod tests { let unaligned = { let mut raw_key = raw_key.as_slice()?; - raw_key.try_advance(4, 0); + raw_key.skip_first(4, 0)?; raw_key.get_prefix(267, 0) }; let aligned = CellBuilder::build_from(unaligned)?; let aligned = aligned.as_slice()?; - assert_eq!( - unaligned.cmp_by_content(&aligned)?, - std::cmp::Ordering::Equal - ); + assert_eq!(unaligned.lex_cmp(&aligned)?, std::cmp::Ordering::Equal); let prefix = Boc::decode_base64("te6ccgEBAwEAjgACB4HQAsACAQCBvwFNima9rQU2tAaEHK+4fSc/aaYcTkT20uyfZuGbZjVMAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAIAgb8RUsb7kteM/ARjNwkzPPYoytZRb4Ic9epNxxLMl/2h7AAAAAAAAAAAAAAAAAAAAADMzMzMzMzMzMzMzMzMzMzO")?; let prefix = { let mut prefix = prefix.as_slice()?; - prefix.try_advance(11, 0); + prefix.skip_first(11, 0)?; prefix.get_prefix(14, 0) }; @@ -1894,7 +1855,7 @@ mod tests { let lcp_aligned = aligned.longest_common_data_prefix(&prefix); assert_eq!( - lcp_unaligned.cmp_by_content(&lcp_aligned)?, + lcp_unaligned.lex_cmp(&lcp_aligned)?, std::cmp::Ordering::Equal ); @@ -1946,7 +1907,7 @@ mod tests { b.store_uint(u64::MAX, 29) }); let mut slice = cell.as_slice()?; - slice.try_advance(1, 0); + slice.skip_first(1, 0)?; assert_eq!(slice.test_uniform(), Some(true)); Ok(()) @@ -1961,7 +1922,7 @@ mod tests { { let cell1 = build_cell(l); let cell2 = build_cell(r); - cell1.as_slice()?.cmp_by_content(&cell2.as_slice()?) + cell1.as_slice()?.lex_cmp(&cell2.as_slice()?) } assert_eq!( diff --git a/src/dict/aug.rs b/src/dict/aug.rs index 930172ba..06385ab5 100644 --- a/src/dict/aug.rs +++ b/src/dict/aug.rs @@ -53,7 +53,7 @@ pub struct AugDict { impl ExactSize for AugDict { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { self.dict.exact_size() + self.extra.exact_size() } } @@ -188,8 +188,8 @@ where Some(root) => { let slice = &mut ok!(root.as_slice()); let prefix = ok!(read_label(slice, K::BITS)); - if prefix.remaining_bits() != K::BITS { - ok!(slice.advance(0, 2)); + if prefix.size_bits() != K::BITS { + ok!(slice.skip_first(0, 2)); } ok!(A::load_from(slice)) } @@ -211,10 +211,8 @@ where let root = *slice; let label = ok!(read_label(slice, key_bit_len)); - let extra = if label.remaining_bits() != key_bit_len { - if !slice.try_advance(0, 2) { - return Err(Error::CellUnderflow); - } + let extra = if label.size_bits() != key_bit_len { + ok!(slice.skip_first(0, 2)); ok!(A::load_from(slice)) } else { let extra = ok!(A::load_from(slice)); @@ -222,8 +220,8 @@ where extra }; - let root_bits = root.remaining_bits() - slice.remaining_bits(); - let root_refs = root.remaining_refs() - slice.remaining_refs(); + let root_bits = root.size_bits() - slice.size_bits(); + let root_refs = root.size_refs() - slice.size_refs(); let mut b = CellBuilder::new(); ok!(b.store_slice(root.get_prefix(root_bits, root_refs))); diff --git a/src/dict/mod.rs b/src/dict/mod.rs index c9967e6c..fa77055f 100644 --- a/src/dict/mod.rs +++ b/src/dict/mod.rs @@ -147,19 +147,17 @@ fn split_edge( context: &mut dyn CellContext, ) -> Result { // Advance the key - let prev_key_bit_len = key.remaining_bits(); - if !key.try_advance(lcp.remaining_bits() + 1, 0) { - return Err(Error::CellUnderflow); - } + let prev_key_bit_len = key.size_bits(); + ok!(key.skip_first(lcp.size_bits() + 1, 0)); // Read the next bit from the data - prefix.try_advance(lcp.remaining_bits(), 0); + prefix.skip_first(lcp.size_bits(), 0).ok(); let old_to_right = ok!(prefix.load_bit()); // Create a leaf for the old value - let mut left = ok!(make_leaf(prefix, key.remaining_bits(), data, context)); + let mut left = ok!(make_leaf(prefix, key.size_bits(), data, context)); // Create a leaf for the right value - let mut right = ok!(make_leaf(key, key.remaining_bits(), value, context)); + let mut right = ok!(make_leaf(key, key.size_bits(), value, context)); // The part that starts with 1 goes to the right cell if old_to_right { @@ -186,21 +184,19 @@ fn split_aug_edge( context: &mut dyn CellContext, ) -> Result { // Advance the key - let prev_key_bit_len = key.remaining_bits(); - if !key.try_advance(lcp.remaining_bits() + 1, 0) { - return Err(Error::CellUnderflow); - } + let prev_key_bit_len = key.size_bits(); + ok!(key.skip_first(lcp.size_bits() + 1, 0)); // Read the next bit from the data - prefix.try_advance(lcp.remaining_bits(), 0); + prefix.skip_first(lcp.size_bits(), 0).ok(); let old_to_right = ok!(prefix.load_bit()); // Create a leaf for the old value - let mut left = ok!(make_leaf(prefix, key.remaining_bits(), data, context)); + let mut left = ok!(make_leaf(prefix, key.size_bits(), data, context)); // Create a leaf for the new value let mut right = ok!(make_leaf_with_extra( key, - key.remaining_bits(), + key.size_bits(), extra, value, context @@ -212,8 +208,8 @@ fn split_aug_edge( let left_slice = &mut ok!(left.as_slice()); let right_slice = &mut ok!(right.as_slice()); - ok!(read_label(left_slice, key.remaining_bits())); - ok!(read_label(right_slice, key.remaining_bits())); + ok!(read_label(left_slice, key.size_bits())); + ok!(read_label(right_slice, key.size_bits())); // Create fork edge let mut builder = CellBuilder::new(); @@ -275,12 +271,10 @@ pub fn dict_load_from_root( let mut root = *slice; let label = ok!(read_label(slice, key_bit_len)); - if label.remaining_bits() != key_bit_len { - if !slice.try_advance(0, 2) { - return Err(Error::CellUnderflow); - } - let root_bits = root.remaining_bits() - slice.remaining_bits(); - let root_refs = root.remaining_refs() - slice.remaining_refs(); + if label.size_bits() != key_bit_len { + ok!(slice.skip_first(0, 2)); + let root_bits = root.size_bits() - slice.size_bits(); + let root_refs = root.size_refs() - slice.size_refs(); root = root.get_prefix(root_bits, root_refs) } else { slice.load_remaining(); @@ -343,7 +337,7 @@ fn rebuild_aug_dict_from_stack( let last_data_slice = ok!(last.data.as_slice()); let last_label = ok!(read_label(&mut last_data_slice.clone(), last.key_bit_len)); - let child_key_bit_len = last.key_bit_len - last_label.remaining_bits() - 1; + let child_key_bit_len = last.key_bit_len - last_label.size_bits() - 1; let left_slice = &mut left.as_slice()?; let right_slice = &mut right.as_slice()?; @@ -401,7 +395,7 @@ impl Segment<'_> { .and_then(CellSlice::new)), None => return Err(Error::CellUnderflow), }; - let rem = ok!(read_label(&mut opposite, key.remaining_bits())); + let rem = ok!(read_label(&mut opposite, key.size_bits())); // Build an edge cell let mut builder = CellBuilder::new(); @@ -426,7 +420,7 @@ fn write_label(key: &CellSlice, key_bit_len: u16, label: &mut CellBuilder) -> Re let bits_for_len = (16 - key_bit_len.leading_zeros()) as u16; - let remaining_bits = key.remaining_bits(); + let remaining_bits = key.size_bits(); let hml_short_len = 2 + 2 * remaining_bits; let hml_long_len = 2 + bits_for_len + remaining_bits; @@ -464,7 +458,7 @@ fn write_label_parts( let bits_for_len = (16 - key_bit_len.leading_zeros()) as u16; - let remaining_bits = pfx.remaining_bits() + 1 + rem.remaining_bits(); + let remaining_bits = pfx.size_bits() + 1 + rem.size_bits(); let hml_short_len = 2 + 2 * remaining_bits; let hml_long_len = 2 + bits_for_len + remaining_bits; @@ -532,11 +526,8 @@ fn read_hml_short<'a>(label: &mut CellSlice<'a>) -> Result, Error> len += 1; } let result = *label; - if label.try_advance(len, 0) { - Ok(result.get_prefix(len, 0)) - } else { - Err(Error::CellUnderflow) - } + ok!(label.skip_first(len, 0)); + Ok(result.get_prefix(len, 0)) } fn write_hml_long_tag(len: u16, bits_for_len: u16, label: &mut CellBuilder) -> Result<(), Error> { @@ -548,11 +539,8 @@ fn write_hml_long_tag(len: u16, bits_for_len: u16, label: &mut CellBuilder) -> R fn read_hml_long<'a>(label: &mut CellSlice<'a>, bits_for_len: u16) -> Result, Error> { let len = ok!(label.load_uint(bits_for_len)) as u16; let result = *label; - if label.try_advance(len, 0) { - Ok(result.get_prefix(len, 0)) - } else { - Err(Error::CellUnderflow) - } + ok!(label.skip_first(len, 0)); + Ok(result.get_prefix(len, 0)) } fn write_hml_same( diff --git a/src/dict/ops/build.rs b/src/dict/ops/build.rs index 178d317e..eec3f506 100644 --- a/src/dict/ops/build.rs +++ b/src/dict/ops/build.rs @@ -77,7 +77,7 @@ where // Write the common prefix as a label let mut common_prefix = prefix_slice; - ok!(common_prefix.advance(key_offset, 0)); // TODO: Unwrap + ok!(common_prefix.skip_first(key_offset, 0)); // TODO: Unwrap ok!(write_label( &common_prefix.get_prefix(label_len, 0), key_bit_len, @@ -85,7 +85,7 @@ where )); // Build leaf from value - ok!(prefix_slice.advance(split_at + 1, 0)); // TODO: Unwrap + ok!(prefix_slice.skip_first(split_at + 1, 0)); // TODO: Unwrap let value = ok!(make_leaf(&prefix_slice, leaf_key_bit_len, &value, context)); result_prefix = prefix; @@ -94,7 +94,7 @@ where Self::Node { prefix, value, .. } => { // Write the common prefix as a label let mut common_prefix = prefix.as_data_slice(); - ok!(common_prefix.advance(key_offset, 0)); // TODO: Unwrap + ok!(common_prefix.skip_first(key_offset, 0)); // TODO: Unwrap ok!(write_label( &common_prefix.get_prefix(label_len, 0), key_bit_len, @@ -111,7 +111,7 @@ where let left_cell = match self { Self::Leaf { prefix, value, .. } => { let mut prefix_slice = prefix.as_data_slice(); - ok!(prefix_slice.advance(split_at + 1, 0)); // TODO: Unwrap + ok!(prefix_slice.skip_first(split_at + 1, 0)); // TODO: Unwrap ok!(make_leaf(&prefix_slice, leaf_key_bit_len, &value, context)) } Self::Node { value, .. } => value, @@ -155,7 +155,7 @@ where let right_prefix = prefix.as_data_slice(); let lcp = left_prefix.longest_common_data_prefix(&right_prefix); - lcp_len = lcp.remaining_bits(); + lcp_len = lcp.size_bits(); if lcp_len <= last.prev_lcp_len() { // LCP decreased, we are not able to group the current item to the last one. @@ -300,7 +300,7 @@ where // Write the common prefix as a label let mut common_prefix = prefix_slice; - ok!(common_prefix.advance(key_offset, 0)); // TODO: Unwrap + ok!(common_prefix.skip_first(key_offset, 0)); // TODO: Unwrap ok!(write_label( &common_prefix.get_prefix(label_len, 0), key_bit_len, @@ -308,11 +308,11 @@ where )); // Build leaf from value - ok!(prefix_slice.advance(split_at + 1, 0)); // TODO: Unwrap + ok!(prefix_slice.skip_first(split_at + 1, 0)); // TODO: Unwrap let value = { let mut builder = CellBuilder::new(); ok!(write_label(&prefix_slice, leaf_key_bit_len, &mut builder)); - right_extra_offset = (builder.bit_len(), 0u8); + right_extra_offset = (builder.size_bits(), 0u8); ok!(extra.store_into(&mut builder, context)); ok!(value.store_into(&mut builder, context)); ok!(builder.build_ext(context)) @@ -329,7 +329,7 @@ where } => { // Write the common prefix as a label let mut common_prefix = prefix.as_data_slice(); - ok!(common_prefix.advance(key_offset, 0)); // TODO: Unwrap + ok!(common_prefix.skip_first(key_offset, 0)); // TODO: Unwrap ok!(write_label( &common_prefix.get_prefix(label_len, 0), key_bit_len, @@ -353,11 +353,11 @@ where .. } => { let mut prefix_slice = prefix.as_data_slice(); - ok!(prefix_slice.advance(split_at + 1, 0)); // TODO: Unwrap + ok!(prefix_slice.skip_first(split_at + 1, 0)); // TODO: Unwrap let mut builder = CellBuilder::new(); ok!(write_label(&prefix_slice, leaf_key_bit_len, &mut builder)); - left_extra_offset = (builder.bit_len(), 0u8); + left_extra_offset = (builder.size_bits(), 0u8); ok!(extra.store_into(&mut builder, context)); ok!(value.store_into(&mut builder, context)); ok!(builder.build_ext(context)) @@ -376,13 +376,17 @@ where ok!(builder.store_reference(left_cell.clone())); ok!(builder.store_reference(right_cell.clone())); - let extra_offset = builder.bit_len(); + let extra_offset = builder.size_bits(); let mut left_extra_slice = ok!(left_cell.as_slice()); - left_extra_slice.try_advance(left_extra_offset.0, left_extra_offset.1); + left_extra_slice + .skip_first(left_extra_offset.0, left_extra_offset.1) + .ok(); let mut right_extra_slice = ok!(right_cell.as_slice()); - right_extra_slice.try_advance(right_extra_offset.0, right_extra_offset.1); + right_extra_slice + .skip_first(right_extra_offset.0, right_extra_offset.1) + .ok(); ok!(comparator( &mut left_extra_slice, @@ -426,7 +430,7 @@ where let right_prefix = prefix.as_data_slice(); let lcp = left_prefix.longest_common_data_prefix(&right_prefix); - lcp_len = lcp.remaining_bits(); + lcp_len = lcp.size_bits(); if lcp_len <= last.prev_lcp_len() { // LCP decreased, we are not able to group the current item to the last one. diff --git a/src/dict/ops/find.rs b/src/dict/ops/find.rs index 8c903dd2..be1d3b55 100644 --- a/src/dict/ops/find.rs +++ b/src/dict/ops/find.rs @@ -12,7 +12,7 @@ pub fn dict_find_owned( signed: bool, context: &mut dyn CellContext, ) -> Result, Error> { - if key.remaining_bits() != key_bit_len { + if key.size_bits() != key_bit_len { return Err(Error::CellUnderflow); } @@ -38,18 +38,18 @@ pub fn dict_find_owned( let mut remaining_data = ok!(data.as_slice()); // Read the next part of the key from the current data - let prefix = &mut ok!(read_label(&mut remaining_data, key.remaining_bits())); + let prefix = &mut ok!(read_label(&mut remaining_data, key.size_bits())); // Match the prefix with the key let lcp = key.longest_common_data_prefix(prefix); - let lcp_len = lcp.remaining_bits(); - match lcp_len.cmp(&key.remaining_bits()) { + let lcp_len = lcp.size_bits(); + match lcp_len.cmp(&key.size_bits()) { // If all bits match, an existing value was found std::cmp::Ordering::Equal => break Leaf::Value(remaining_data.range()), // LCP is less than prefix, an edge to slice was found std::cmp::Ordering::Less => { // LCP is less than prefix, an edge to slice was found - if lcp_len < prefix.remaining_bits() { + if lcp_len < prefix.size_bits() { let mut next_branch = Branch::from(ok!(key.get_bit(lcp_len))); if signed && stack.is_empty() && lcp_len == 0 { next_branch = next_branch.reversed(); @@ -65,7 +65,7 @@ pub fn dict_find_owned( } // Remove the LCP from the key - key.try_advance(lcp.remaining_bits(), 0); + key.skip_first(lcp.size_bits(), 0).ok(); // Load the next branch let next_branch = Branch::from(ok!(key.load_bit())); @@ -79,7 +79,7 @@ pub fn dict_find_owned( stack.push(Segment { data, next_branch, - key_bit_len: key.remaining_bits(), + key_bit_len: key.size_bits(), }); prev = Some((data, next_branch)); data = child; @@ -117,7 +117,7 @@ pub fn dict_find_owned( if let Leaf::Divergence(next_branch) = value_range { if next_branch == rev_direction { // Skip rewinding if the key diverged towards the opposite direction. - let remaining_bits = key.remaining_bits(); + let remaining_bits = key.size_bits(); let prefix_len = key_bit_len - remaining_bits; original_key_range = original_key_range.get_prefix(prefix_len, 0); let _compatibility_gas = ok!(context.load_dyn_cell(data, LoadMode::UseGas)); @@ -178,10 +178,10 @@ pub fn dict_find_owned( ok!(result_key.store_slice_data(prefix)); } - match remaining_bits.checked_sub(prefix.remaining_bits()) { + match remaining_bits.checked_sub(prefix.size_bits()) { Some(0) => break remaining_data.range(), Some(remaining) => { - if remaining_data.remaining_refs() < 2 { + if remaining_data.size_refs() < 2 { return Err(Error::CellUnderflow); } remaining_bits = remaining - 1; @@ -237,10 +237,10 @@ pub fn dict_find_bound<'a: 'b, 'b>( ok!(key.store_slice_data(prefix)); } - match key_bit_len.checked_sub(prefix.remaining_bits()) { + match key_bit_len.checked_sub(prefix.size_bits()) { Some(0) => break, Some(remaining) => { - if data.remaining_refs() < 2 { + if data.size_refs() < 2 { return Err(Error::CellUnderflow); } key_bit_len = remaining - 1; @@ -291,10 +291,10 @@ pub fn dict_find_bound_owned( ok!(key.store_slice_data(prefix)); } - match key_bit_len.checked_sub(prefix.remaining_bits()) { + match key_bit_len.checked_sub(prefix.size_bits()) { Some(0) => break, Some(remaining) => { - if data.remaining_refs() < 2 { + if data.size_refs() < 2 { return Err(Error::CellUnderflow); } key_bit_len = remaining - 1; diff --git a/src/dict/ops/get.rs b/src/dict/ops/get.rs index f94ffcd6..0ee53e37 100644 --- a/src/dict/ops/get.rs +++ b/src/dict/ops/get.rs @@ -9,7 +9,7 @@ pub fn dict_get<'a: 'b, 'b>( mut key: CellSlice<'b>, context: &mut dyn CellContext, ) -> Result>, Error> { - if key.remaining_bits() != key_bit_len { + if key.size_bits() != key_bit_len { return Err(Error::CellUnderflow); } @@ -23,7 +23,7 @@ pub fn dict_get<'a: 'b, 'b>( // Try to find the required leaf let is_key_empty = loop { // Read the key part written in the current edge - let prefix = ok!(read_label(&mut data, key.remaining_bits())); + let prefix = ok!(read_label(&mut data, key.size_bits())); // Remove this prefix from the key match key.strip_data_prefix(&prefix) { @@ -31,7 +31,7 @@ pub fn dict_get<'a: 'b, 'b>( if stripped_key.is_data_empty() { // All key parts were collected <=> value found break true; - } else if data.remaining_refs() < 2 { + } else if data.size_refs() < 2 { // Reached leaf while key was not fully constructed return Ok(None); } else { @@ -62,7 +62,7 @@ pub fn dict_get_owned( mut key: CellSlice<'_>, context: &mut dyn CellContext, ) -> Result, Error> { - if key.remaining_bits() != key_bit_len { + if key.size_bits() != key_bit_len { return Err(Error::CellUnderflow); } @@ -76,7 +76,7 @@ pub fn dict_get_owned( // Try to find the required leaf let is_key_empty = loop { // Read the key part written in the current edge - let prefix = ok!(read_label(&mut data, key.remaining_bits())); + let prefix = ok!(read_label(&mut data, key.size_bits())); // Remove this prefix from the key match key.strip_data_prefix(&prefix) { @@ -84,7 +84,7 @@ pub fn dict_get_owned( if stripped_key.is_data_empty() { // All key parts were collected <=> value found break true; - } else if data.remaining_refs() < 2 { + } else if data.size_refs() < 2 { // Reached leaf while key was not fully constructed return Ok(None); } else { @@ -136,7 +136,7 @@ pub fn dict_get_subdict<'a: 'b, 'b>( match dict { None => Ok(None), Some(cell) => { - let prefix_len = prefix.remaining_bits(); + let prefix_len = prefix.size_bits(); if prefix_len == 0 || key_bit_len < prefix_len { return Ok(Some(cell.clone())); } @@ -151,15 +151,15 @@ pub fn dict_get_subdict<'a: 'b, 'b>( // Try to find the required root let subtree = loop { // Read the key part written in the current edge - let label = &mut ok!(read_label(&mut data, prefix.remaining_bits())); + let label = &mut ok!(read_label(&mut data, prefix.size_bits())); let lcp = prefix.longest_common_data_prefix(label); - match lcp.remaining_bits().cmp(&prefix.remaining_bits()) { + match lcp.size_bits().cmp(&prefix.size_bits()) { std::cmp::Ordering::Equal => { // Found exact key - let new_leaf = ok!(make_leaf(label, lcp.remaining_bits(), &data, context)); + let new_leaf = ok!(make_leaf(label, lcp.size_bits(), &data, context)); break new_leaf; } - std::cmp::Ordering::Less if lcp.remaining_bits() < label.remaining_bits() => { + std::cmp::Ordering::Less if lcp.size_bits() < label.size_bits() => { // Have to split edge let value = ok!(CellBuilder::new().build_ext(context)); let split_edge = @@ -170,7 +170,7 @@ pub fn dict_get_subdict<'a: 'b, 'b>( if data.cell().reference_count() != 2 { return Err(Error::CellUnderflow); } - prefix.try_advance(lcp.remaining_bits(), 0); + prefix.skip_first(lcp.size_bits(), 0).ok(); let next_branch = match prefix.load_bit() { Ok(bit) => Branch::from(bit), Err(e) => return Err(e), diff --git a/src/dict/ops/insert.rs b/src/dict/ops/insert.rs index b136be6f..1d00a650 100644 --- a/src/dict/ops/insert.rs +++ b/src/dict/ops/insert.rs @@ -15,7 +15,7 @@ pub fn dict_insert( mode: SetMode, context: &mut dyn CellContext, ) -> Result { - if key.remaining_bits() != key_bit_len { + if key.size_bits() != key_bit_len { return Err(Error::CellUnderflow); } @@ -35,11 +35,11 @@ pub fn dict_insert( let mut remaining_data = ok!(data.as_slice()); // Read the next part of the key from the current data - let prefix = &mut ok!(read_label(&mut remaining_data, key.remaining_bits())); + let prefix = &mut ok!(read_label(&mut remaining_data, key.size_bits())); // Match the prefix with the key let lcp = key.longest_common_data_prefix(prefix); - match lcp.remaining_bits().cmp(&key.remaining_bits()) { + match lcp.size_bits().cmp(&key.size_bits()) { // If all bits match, an existing value was found std::cmp::Ordering::Equal => { // Check if we can replace the value @@ -48,10 +48,10 @@ pub fn dict_insert( return Ok(false); } // Replace the existing value - break ok!(make_leaf(prefix, key.remaining_bits(), value, context)); + break ok!(make_leaf(prefix, key.size_bits(), value, context)); } // LCP is less than prefix, an edge to slice was found - std::cmp::Ordering::Less if lcp.remaining_bits() < prefix.remaining_bits() => { + std::cmp::Ordering::Less if lcp.size_bits() < prefix.size_bits() => { // Check if we can add a new value if !mode.can_add() { // TODO: what is the desired behavior for root as a library? @@ -74,8 +74,8 @@ pub fn dict_insert( } // Remove the LCP from the key - let key_bit_len = key.remaining_bits(); - key.try_advance(lcp.remaining_bits(), 0); + let key_bit_len = key.size_bits(); + key.skip_first(lcp.size_bits(), 0).ok(); // Load the next branch let next_branch = match key.load_bit() { @@ -121,7 +121,7 @@ pub fn aug_dict_insert( comparator: AugDictFn, context: &mut dyn CellContext, ) -> Result { - if key.remaining_bits() != key_bit_len { + if key.size_bits() != key_bit_len { return Err(Error::CellUnderflow); } @@ -149,10 +149,10 @@ pub fn aug_dict_insert( let leaf = loop { let mut remaining_data = ok!(data.as_slice()); // Read the next part of the key from the current data - let prefix = &mut ok!(read_label(&mut remaining_data, key.remaining_bits())); + let prefix = &mut ok!(read_label(&mut remaining_data, key.size_bits())); // Match the prefix with the key let lcp = key.longest_common_data_prefix(prefix); - match lcp.remaining_bits().cmp(&key.remaining_bits()) { + match lcp.size_bits().cmp(&key.size_bits()) { // If all bits match, an existing value was found std::cmp::Ordering::Equal => { // Check if we can replace the value @@ -163,14 +163,14 @@ pub fn aug_dict_insert( // Replace the existing value break ok!(make_leaf_with_extra( prefix, - key.remaining_bits(), + key.size_bits(), extra, value, context )); } // LCP is less than prefix, an edge to slice was found - std::cmp::Ordering::Less if lcp.remaining_bits() < prefix.remaining_bits() => { + std::cmp::Ordering::Less if lcp.size_bits() < prefix.size_bits() => { // Check if we can add a new value if !mode.can_add() { // TODO: what is the desired behavior for root as a library? @@ -195,8 +195,8 @@ pub fn aug_dict_insert( } // Remove the LCP from the key - let key_bit_len = key.remaining_bits(); - key.try_advance(lcp.remaining_bits(), 0); + let key_bit_len = key.size_bits(); + key.skip_first(lcp.size_bits(), 0).ok(); // Load the next branch let next_branch = match key.load_bit() { Ok(bit) => Branch::from(bit), @@ -258,7 +258,7 @@ pub fn dict_insert_owned( } } - if key.remaining_bits() != key_bit_len { + if key.size_bits() != key_bit_len { return Err(Error::CellUnderflow); } @@ -278,11 +278,11 @@ pub fn dict_insert_owned( let mut remaining_data = ok!(data.as_slice()); // Read the next part of the key from the current data - let prefix = &mut ok!(read_label(&mut remaining_data, key.remaining_bits())); + let prefix = &mut ok!(read_label(&mut remaining_data, key.size_bits())); // Match the prefix with the key let lcp = key.longest_common_data_prefix(prefix); - match lcp.remaining_bits().cmp(&key.remaining_bits()) { + match lcp.size_bits().cmp(&key.size_bits()) { // If all bits match, an existing value was found std::cmp::Ordering::Equal => { // Check if we can replace the value @@ -298,12 +298,12 @@ pub fn dict_insert_owned( } // Replace the existing value break ( - ok!(make_leaf(prefix, key.remaining_bits(), value, context)), + ok!(make_leaf(prefix, key.size_bits(), value, context)), Some(remaining_data.range()), ); } // LCP is less than prefix, an edge to slice was found - std::cmp::Ordering::Less if lcp.remaining_bits() < prefix.remaining_bits() => { + std::cmp::Ordering::Less if lcp.size_bits() < prefix.size_bits() => { // Check if we can add a new value if !mode.can_add() { // TODO: what is the desired behavior for root as a library? @@ -329,8 +329,8 @@ pub fn dict_insert_owned( } // Remove the LCP from the key - let key_bit_len = key.remaining_bits(); - key.try_advance(lcp.remaining_bits(), 0); + let key_bit_len = key.size_bits(); + key.skip_first(lcp.size_bits(), 0).ok(); // Load the next branch let next_branch = match key.load_bit() { diff --git a/src/dict/ops/remove.rs b/src/dict/ops/remove.rs index 5551e7dd..f083dcaa 100644 --- a/src/dict/ops/remove.rs +++ b/src/dict/ops/remove.rs @@ -14,7 +14,7 @@ pub fn dict_remove_owned( allow_subtree: bool, context: &mut dyn CellContext, ) -> Result, Error> { - if !allow_subtree && key.remaining_bits() != key_bit_len { + if !allow_subtree && key.size_bits() != key_bit_len { return Err(Error::CellUnderflow); } @@ -52,7 +52,7 @@ pub fn aug_dict_remove_owned( comparator: AugDictFn, context: &mut dyn CellContext, ) -> Result, Error> { - if !allow_subtree && key.remaining_bits() != key_bit_len { + if !allow_subtree && key.size_bits() != key_bit_len { return Err(Error::CellUnderflow); } @@ -92,20 +92,20 @@ fn dict_find_value_to_remove<'a>( let mut stack = Vec::::new(); - let mut prev_key_bit_len = key.remaining_bits(); + let mut prev_key_bit_len = key.size_bits(); let removed = loop { let mut remaining_data: CellSlice<'_> = ok!(data.as_slice()); // Read the next part of the key from the current data - let prefix = &mut ok!(read_label(&mut remaining_data, key.remaining_bits())); + let prefix = &mut ok!(read_label(&mut remaining_data, key.size_bits())); // Match the prefix with the key let lcp = key.longest_common_data_prefix(prefix); - match lcp.remaining_bits().cmp(&key.remaining_bits()) { + match lcp.size_bits().cmp(&key.size_bits()) { // If all bits match, an existing value was found std::cmp::Ordering::Equal => break remaining_data.range(), // LCP is less than prefix, an edge to slice was found - std::cmp::Ordering::Less if lcp.remaining_bits() < prefix.remaining_bits() => { + std::cmp::Ordering::Less if lcp.size_bits() < prefix.size_bits() => { return Ok(None); } // The key contains the entire prefix, but there are still some bits left @@ -116,8 +116,8 @@ fn dict_find_value_to_remove<'a>( } // Remove the LCP from the key - prev_key_bit_len = key.remaining_bits(); - key.try_advance(lcp.remaining_bits(), 0); + prev_key_bit_len = key.size_bits(); + key.skip_first(lcp.size_bits(), 0).ok(); // Load the next branch let next_branch = Branch::from(ok!(key.load_bit())); @@ -177,10 +177,10 @@ pub fn dict_remove_bound_owned( ok!(key.store_slice_data(prefix)); } - match key_bit_len.checked_sub(prefix.remaining_bits()) { + match key_bit_len.checked_sub(prefix.size_bits()) { Some(0) => break remaining_data.range(), Some(remaining) => { - if remaining_data.remaining_refs() < 2 { + if remaining_data.size_refs() < 2 { return Err(Error::CellUnderflow); } prev_key_bit_len = key_bit_len; diff --git a/src/dict/ops/split_merge.rs b/src/dict/ops/split_merge.rs index 4194720d..dbd30be0 100644 --- a/src/dict/ops/split_merge.rs +++ b/src/dict/ops/split_merge.rs @@ -24,7 +24,7 @@ pub fn dict_split_by_prefix( let subdict_bit_len = match root_label.strip_data_prefix(key_prefix) { // Root label == key prefix Some(root_label_rem) if root_label_rem.is_data_empty() => { - match key_bit_len.checked_sub(root_label.remaining_bits() + 1) { + match key_bit_len.checked_sub(root_label.size_bits() + 1) { Some(bit_len) => bit_len, None => return Err(Error::CellUnderflow), } @@ -89,7 +89,7 @@ pub fn dict_merge( let mut right_dict_iter = RawIter::new(right, key_bit_length); while let Some(Ok((key, value))) = right_dict_iter.next() { - let current_bit_len = key.bit_len(); + let current_bit_len = key.size_bits(); dict_insert( left, diff --git a/src/dict/raw.rs b/src/dict/raw.rs index 9888e56c..ffc4709e 100644 --- a/src/dict/raw.rs +++ b/src/dict/raw.rs @@ -40,8 +40,8 @@ pub struct RawDict(pub(crate) Option); impl ExactSize for RawDict { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { + fn exact_size(&self) -> Size { + Size { bits: 1, refs: self.0.is_some() as u8, } @@ -794,7 +794,7 @@ impl<'a> RawIter<'a> { Ok((key, slice)) => { let parent = match self.segments.last() { Some(segment) => { - let refs_offset = segment.data.refs_offset(); + let refs_offset = segment.data.offset_refs(); debug_assert!( segment.prefix.is_some() && (refs_offset == 1 || refs_offset == 2) ); @@ -864,7 +864,7 @@ impl<'a> Iterator for RawIter<'a> { break segment; }; - let refs_offset = segment.data.refs_offset(); + let refs_offset = segment.data.offset_refs(); if refs_offset < 2 { // Found the latest unprocessed slice let remaining_bit_len = segment.remaining_bit_len; @@ -873,7 +873,7 @@ impl<'a> Iterator for RawIter<'a> { ^ (signed && is_root && prefix.is_data_empty()); let data = ok!(segment.data.cell().get_reference_as_slice(next_bit as u8)); - segment.data.try_advance(0, 1); + segment.data.skip_first(0, 1).ok(); ok!(builder.rewind(to_rewind)); ok!(builder.store_bit(next_bit)); @@ -886,7 +886,7 @@ impl<'a> Iterator for RawIter<'a> { break (unsafe { segments.last_mut().unwrap_unchecked() }); } else { // Rewind prefix - to_rewind += prefix.remaining_bits(); + to_rewind += prefix.size_bits(); // Pop processed segments segments.pop(); // Rewind reference bit (if any) @@ -898,10 +898,7 @@ impl<'a> Iterator for RawIter<'a> { let prefix = ok!(read_label(&mut segment.data, segment.remaining_bit_len)); // Check remaining bits - return match segment - .remaining_bit_len - .checked_sub(prefix.remaining_bits()) - { + return match segment.remaining_bit_len.checked_sub(prefix.size_bits()) { // Return value if there are no remaining bits to read Some(0) => { // Try to store the last prefix into the result key @@ -918,7 +915,7 @@ impl<'a> Iterator for RawIter<'a> { } // Append prefix to builder and proceed to the next segment Some(remaining) => { - if segment.data.remaining_refs() < 2 { + if segment.data.size_refs() < 2 { return Err(Error::CellUnderflow); } @@ -1114,7 +1111,7 @@ impl<'a> Iterator for UnionRawIter<'a> { reversed ^= left_is_neg != right_is_neg; } - let cmp = match left_key.cmp_by_content_only(&right_key) { + let cmp = match left_key.lex_cmp(&right_key) { Ok(cmp) => cmp, Err(e) => return Some(Err(self.finish(e))), }; @@ -1285,7 +1282,7 @@ impl<'a> Iterator for RawOwnedValues<'a> { Ok(slice) => { let parent = match self.inner.segments.last() { Some(segment) => { - let refs_offset = segment.data.refs_offset(); + let refs_offset = segment.data.offset_refs(); debug_assert!(refs_offset > 0); match segment.data.cell().reference_cloned(refs_offset - 1) { Some(cell) => cell, @@ -1416,11 +1413,11 @@ impl<'a> Iterator for RawValues<'a> { return Ok(None); }; - if segment.data.bits_offset() == 0 { + if segment.data.offset_bits() == 0 { break segment; } - let refs_offset = segment.data.refs_offset(); + let refs_offset = segment.data.offset_refs(); if refs_offset < 2 { // Found the latest unprocessed slice let remaining_bit_len = segment.remaining_bit_len; @@ -1428,7 +1425,7 @@ impl<'a> Iterator for RawValues<'a> { ^ reverse ^ (signed && is_root && segment.data.is_data_empty()); let data = ok!(segment.data.cell().get_reference_as_slice(next_bit as u8)); - segment.data.try_advance(0, 1); + segment.data.skip_first(0, 1).ok(); segments.push(ValuesSegment { data, @@ -1445,10 +1442,7 @@ impl<'a> Iterator for RawValues<'a> { let prefix = ok!(read_label(&mut segment.data, segment.remaining_bit_len)); // Check remaining bits - return match segment - .remaining_bit_len - .checked_sub(prefix.remaining_bits()) - { + return match segment.remaining_bit_len.checked_sub(prefix.size_bits()) { // Return value if there are no remaining bits to read Some(0) => { let data = segment.data; @@ -1458,7 +1452,7 @@ impl<'a> Iterator for RawValues<'a> { } // Append prefix to builder and proceed to the next segment Some(remaining) => { - if segment.data.remaining_refs() < 2 { + if segment.data.size_refs() < 2 { return Err(Error::CellUnderflow); } segment.remaining_bit_len = remaining - 1; @@ -1534,7 +1528,7 @@ mod tests { total += 1; let (key, value) = item?; let key = key.build()?; - assert_eq!(value.remaining_bits(), 1); + assert_eq!(value.size_bits(), 1); assert_eq!(key.bit_len(), 32); let key = key.as_slice()?.load_u32()?; assert_eq!(key, i as u32); @@ -1566,7 +1560,7 @@ mod tests { .get(build_cell(|b| b.store_u32(123)).as_slice()?) .unwrap() .unwrap(); - assert_eq!(value.remaining_bits(), 1); + assert_eq!(value.size_bits(), 1); assert_eq!(value.load_bit(), Ok(true)); Ok(()) @@ -1581,13 +1575,13 @@ mod tests { // dict.add(key.as_slice()?, false)?; let mut value = dict.get(key.as_slice()?)?.unwrap(); - assert_eq!(value.remaining_bits(), 1); + assert_eq!(value.size_bits(), 1); assert_eq!(value.load_bit(), Ok(false)); // dict.add(key.as_slice()?, true)?; let mut value = dict.get(key.as_slice()?)?.unwrap(); - assert_eq!(value.remaining_bits(), 1); + assert_eq!(value.size_bits(), 1); assert_eq!(value.load_bit(), Ok(false)); Ok(()) @@ -1743,10 +1737,7 @@ mod tests { let (rev_key, rev_value) = rev_iter_items.next().unwrap().unwrap(); assert_eq!(key, rev_key); - assert_eq!( - value.cmp_by_content(&rev_value), - Ok(std::cmp::Ordering::Equal) - ); + assert_eq!(value.lex_cmp(&rev_value), Ok(std::cmp::Ordering::Equal)); let key = { let key_cell = key.build()?; @@ -1762,7 +1753,7 @@ mod tests { { let mut slice = range.apply(&cell).unwrap(); - assert_eq!(slice.remaining_bits(), 32); + assert_eq!(slice.size_bits(), 32); u32::load_from(&mut slice).unwrap(); } @@ -1782,7 +1773,7 @@ mod tests { let (cell, range) = value_owned.unwrap(); let value_owned = range.apply(&cell).unwrap(); assert_eq!( - value_ref.cmp_by_content(&value_owned), + value_ref.lex_cmp(&value_owned), Ok(std::cmp::Ordering::Equal) ); } diff --git a/src/dict/typed.rs b/src/dict/typed.rs index 9a52fcf1..f5b8c781 100644 --- a/src/dict/typed.rs +++ b/src/dict/typed.rs @@ -23,8 +23,8 @@ pub struct Dict { impl ExactSize for Dict { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { + fn exact_size(&self) -> Size { + Size { bits: 1, refs: self.root.is_some() as u8, } diff --git a/src/merkle/proof.rs b/src/merkle/proof.rs index e4d0173c..5f2fbd91 100644 --- a/src/merkle/proof.rs +++ b/src/merkle/proof.rs @@ -39,23 +39,24 @@ impl Default for MerkleProofRef<'_> { impl<'a> Load<'a> for MerkleProofRef<'a> { fn load_from(s: &mut CellSlice<'a>) -> Result { - if !s.has_remaining(MerkleProof::BITS, MerkleProof::REFS) { + if !s.is_full() || s.size_bits() != MerkleProof::BITS || s.size_refs() != MerkleProof::REFS + { return Err(Error::CellUnderflow); } - if ok!(s.get_u8(0)) != CellType::MerkleProof.to_byte() { + if !s.cell().descriptor().is_exotic() || ok!(s.get_u8(0)) != CellType::MerkleProof.to_byte() + { return Err(Error::InvalidCell); } let res = Self { - hash: ok!(s.get_u256(8)), - depth: ok!(s.get_u16(8 + 256)), - cell: ok!(s.get_reference(0)), + hash: ok!(s.load_u256()), + depth: ok!(s.load_u16()), + cell: ok!(s.load_reference()), }; - if res.cell.hash(0) == &res.hash - && res.cell.depth(0) == res.depth - && s.try_advance(MerkleProof::BITS, MerkleProof::REFS) - { + debug_assert!(s.is_empty()); + + if res.cell.hash(0) == &res.hash && res.cell.depth(0) == res.depth { Ok(res) } else { Err(Error::InvalidCell) @@ -100,23 +101,24 @@ impl Default for MerkleProof { impl Load<'_> for MerkleProof { fn load_from(s: &mut CellSlice) -> Result { - if !s.has_remaining(Self::BITS, Self::REFS) { + if !s.is_full() || s.size_bits() != MerkleProof::BITS || s.size_refs() != MerkleProof::REFS + { return Err(Error::CellUnderflow); } - if ok!(s.get_u8(0)) != CellType::MerkleProof.to_byte() { + if !s.cell().descriptor().is_exotic() || ok!(s.load_u8()) != CellType::MerkleProof.to_byte() + { return Err(Error::InvalidCell); } let res = Self { - hash: ok!(s.get_u256(8)), - depth: ok!(s.get_u16(8 + 256)), - cell: ok!(s.get_reference_cloned(0)), + hash: ok!(s.load_u256()), + depth: ok!(s.load_u16()), + cell: ok!(s.load_reference_cloned()), }; - if res.cell.as_ref().hash(0) == &res.hash - && res.cell.as_ref().depth(0) == res.depth - && s.try_advance(Self::BITS, Self::REFS) - { + debug_assert!(s.is_empty()); + + if res.cell.hash(0) == &res.hash && res.cell.depth(0) == res.depth { Ok(res) } else { Err(Error::InvalidCell) diff --git a/src/merkle/update.rs b/src/merkle/update.rs index 76b48a2a..5dcb4e45 100644 --- a/src/merkle/update.rs +++ b/src/merkle/update.rs @@ -55,27 +55,30 @@ impl Default for MerkleUpdate { impl Load<'_> for MerkleUpdate { fn load_from(s: &mut CellSlice) -> Result { - if !s.has_remaining(Self::BITS, Self::REFS) { + if !s.is_full() || s.size_bits() != Self::BITS || s.size_refs() != Self::REFS { return Err(Error::CellUnderflow); } - if ok!(s.get_u8(0)) != CellType::MerkleUpdate.to_byte() { + if !s.cell().descriptor().is_exotic() + || ok!(s.load_u8()) != CellType::MerkleUpdate.to_byte() + { return Err(Error::InvalidCell); } let res = Self { - old_hash: ok!(s.get_u256(8)), - new_hash: ok!(s.get_u256(8 + 256)), - old_depth: ok!(s.get_u16(8 + 256 * 2)), - new_depth: ok!(s.get_u16(8 + 256 * 2 + 16)), - old: ok!(s.get_reference_cloned(0)), - new: ok!(s.get_reference_cloned(1)), + old_hash: ok!(s.load_u256()), + new_hash: ok!(s.load_u256()), + old_depth: ok!(s.load_u16()), + new_depth: ok!(s.load_u16()), + old: ok!(s.load_reference_cloned()), + new: ok!(s.load_reference_cloned()), }; + debug_assert!(s.is_data_empty() && s.is_refs_empty()); + if res.old.as_ref().hash(0) == &res.old_hash && res.old.as_ref().depth(0) == res.old_depth && res.new.as_ref().hash(0) == &res.new_hash && res.new.as_ref().depth(0) == res.new_depth - && s.try_advance(Self::BITS, Self::REFS) { Ok(res) } else { diff --git a/src/models/account/mod.rs b/src/models/account/mod.rs index 53632a7a..b0937bb3 100644 --- a/src/models/account/mod.rs +++ b/src/models/account/mod.rs @@ -397,8 +397,8 @@ impl Default for StateInit { impl StateInit { /// Exact size of this value when it is stored in slice. - pub const fn exact_size_const(&self) -> CellSliceSize { - CellSliceSize { + pub const fn exact_size_const(&self) -> Size { + Size { bits: self.bit_len(), refs: self.reference_count(), } @@ -419,7 +419,7 @@ impl StateInit { impl ExactSize for StateInit { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { self.exact_size_const() } } diff --git a/src/models/block/shard_hashes.rs b/src/models/block/shard_hashes.rs index 26785929..d3730db4 100755 --- a/src/models/block/shard_hashes.rs +++ b/src/models/block/shard_hashes.rs @@ -612,18 +612,14 @@ impl<'a> Load<'a> for ShardDescription { } fn parse_block_id(shard: ShardIdent, mut value: CellSlice) -> Result { - if !value.try_advance(ShardDescription::TAG_LEN, 0) { - return Err(Error::CellUnderflow); - } + ok!(value.skip_first(ShardDescription::TAG_LEN, 0)); Ok(BlockId { shard, seqno: ok!(value.load_u32()), root_hash: { // Skip some fields (reg_mc_seqno: u32, start_lt: u64, end_lt: u64) - if !value.try_advance(32 + 64 + 64, 0) { - return Err(Error::CellUnderflow); - } + ok!(value.skip_first(32 + 64 + 64, 0)); ok!(value.load_u256()) }, file_hash: ok!(value.load_u256()), diff --git a/src/models/currency.rs b/src/models/currency.rs index a9ae2e54..d7274ed0 100644 --- a/src/models/currency.rs +++ b/src/models/currency.rs @@ -117,7 +117,7 @@ impl From for CurrencyCollection { impl ExactSize for CurrencyCollection { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { self.tokens.exact_size() + self.other.exact_size() } } @@ -218,7 +218,7 @@ impl From> for ExtraCurrencyCollection { impl ExactSize for ExtraCurrencyCollection { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { self.0.exact_size() } } diff --git a/src/models/message/address.rs b/src/models/message/address.rs index 63a73b5b..39fbcfe5 100644 --- a/src/models/message/address.rs +++ b/src/models/message/address.rs @@ -682,7 +682,7 @@ impl Anycast { /// Constructs anycast info from rewrite prefix. pub fn from_slice(rewrite_prefix: &CellSlice<'_>) -> Result { - let depth = ok!(SplitDepth::from_bit_len(rewrite_prefix.remaining_bits())); + let depth = ok!(SplitDepth::from_bit_len(rewrite_prefix.size_bits())); let mut data = vec![0; (depth.into_bit_len() as usize + 7) / 8]; ok!(rewrite_prefix.get_raw(0, &mut data, depth.into_bit_len())); diff --git a/src/models/message/mod.rs b/src/models/message/mod.rs index 834f7119..3fcb57a4 100644 --- a/src/models/message/mod.rs +++ b/src/models/message/mod.rs @@ -158,7 +158,7 @@ where } None => MessageLayout::compute(info_size, self.init.as_ref(), body_size), }; - let CellSliceSize { bits, refs } = size; + let Size { bits, refs } = size; // Check capacity if !builder.has_capacity(bits, refs) { @@ -372,10 +372,10 @@ impl MessageLayout { /// Computes the number of bits and refs for this layout for the root cell. pub const fn compute_full_size( &self, - info_size: CellSliceSize, + info_size: Size, init: Option<&StateInit>, - body_size: CellSliceSize, - ) -> CellSliceSize { + body_size: Size, + ) -> Size { let l = DetailedMessageLayout::compute(info_size, init, body_size); let mut total = l.info; @@ -402,10 +402,10 @@ impl MessageLayout { /// Computes the most optimal layout of the message parts. /// Also returns the number of bits and refs for the root cell. pub const fn compute( - info_size: CellSliceSize, + info_size: Size, init: Option<&StateInit>, - body_size: CellSliceSize, - ) -> (Self, CellSliceSize) { + body_size: Size, + ) -> (Self, Size) { let l = DetailedMessageLayout::compute(info_size, init, body_size); // Try plain layout @@ -418,7 +418,7 @@ impl MessageLayout { }; return ( layout, - CellSliceSize { + Size { bits: total_bits, refs: total_refs, }, @@ -435,7 +435,7 @@ impl MessageLayout { }; return ( layout, - CellSliceSize { + Size { bits: total_bits, refs: total_refs + 1, }, @@ -452,7 +452,7 @@ impl MessageLayout { }; return ( layout, - CellSliceSize { + Size { bits: total_bits, refs: total_refs + 1, }, @@ -466,7 +466,7 @@ impl MessageLayout { }; ( layout, - CellSliceSize { + Size { bits: l.info.bits, refs: l.info.refs + 2, }, @@ -475,17 +475,13 @@ impl MessageLayout { } struct DetailedMessageLayout { - info: CellSliceSize, - init: CellSliceSize, - body: CellSliceSize, + info: Size, + init: Size, + body: Size, } impl DetailedMessageLayout { - const fn compute( - mut info: CellSliceSize, - init: Option<&StateInit>, - body: CellSliceSize, - ) -> Self { + const fn compute(mut info: Size, init: Option<&StateInit>, body: Size) -> Self { info.bits += 2; // (Maybe X) (1bit) + (Either X) (1bit) let init = match init { @@ -493,7 +489,7 @@ impl DetailedMessageLayout { info.bits += 1; // (Either X) (1bit) init.exact_size_const() } - None => CellSliceSize::ZERO, + None => Size::ZERO, }; Self { info, init, body } @@ -513,8 +509,8 @@ pub enum RelaxedMsgInfo { impl RelaxedMsgInfo { /// Exact size of this value when it is stored in slice. - pub const fn exact_size_const(&self) -> CellSliceSize { - CellSliceSize { + pub const fn exact_size_const(&self) -> Size { + Size { bits: self.bit_len(), refs: self.has_references() as u8, } @@ -538,7 +534,7 @@ impl RelaxedMsgInfo { impl ExactSize for RelaxedMsgInfo { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { self.exact_size_const() } } @@ -595,8 +591,8 @@ pub enum MsgInfo { impl MsgInfo { /// Exact size of this value when it is stored in slice. - pub const fn exact_size_const(&self) -> CellSliceSize { - CellSliceSize { + pub const fn exact_size_const(&self) -> Size { + Size { bits: self.bit_len(), refs: self.has_references() as u8, } @@ -621,7 +617,7 @@ impl MsgInfo { impl ExactSize for MsgInfo { #[inline] - fn exact_size(&self) -> CellSliceSize { + fn exact_size(&self) -> Size { self.exact_size_const() } } diff --git a/src/models/mod.rs b/src/models/mod.rs index 0113bf63..56ef0dae 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::cell::{ - Cell, CellBuilder, CellContext, CellSlice, CellSliceSize, DynCell, EquivalentRepr, Load, Store, + Cell, CellBuilder, CellContext, CellSlice, DynCell, EquivalentRepr, Load, Size, Store, }; use crate::error::Error; use crate::util::*; @@ -49,8 +49,8 @@ pub struct Lazy { impl crate::cell::ExactSize for Lazy { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { bits: 0, refs: 1 } + fn exact_size(&self) -> Size { + Size { bits: 0, refs: 1 } } } diff --git a/src/num/mod.rs b/src/num/mod.rs index 8c99d664..b4210935 100644 --- a/src/num/mod.rs +++ b/src/num/mod.rs @@ -422,8 +422,8 @@ macro_rules! impl_var_uints { impl ExactSize for $ident { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { + fn exact_size(&self) -> Size { + Size { bits: self.bit_len().unwrap_or_default(), refs: 0, } @@ -680,8 +680,8 @@ macro_rules! impl_small_uints { impl ExactSize for $ident { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { bits: $bits, refs: 0 } + fn exact_size(&self) -> Size { + Size { bits: $bits, refs: 0 } } } @@ -784,8 +784,8 @@ impl SplitDepth { impl ExactSize for SplitDepth { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { + fn exact_size(&self) -> Size { + Size { bits: Self::BITS, refs: 0, } diff --git a/src/num/varuint248.rs b/src/num/varuint248.rs index 6a956923..54a39b67 100644 --- a/src/num/varuint248.rs +++ b/src/num/varuint248.rs @@ -1,7 +1,7 @@ use std::mem::MaybeUninit; use std::str::FromStr; -use crate::cell::{CellBuilder, CellContext, CellSlice, CellSliceSize, ExactSize, Load, Store}; +use crate::cell::{CellBuilder, CellContext, CellSlice, ExactSize, Load, Size, Store}; use crate::error::Error; use crate::util::unlikely; @@ -205,8 +205,8 @@ impl_from! { u8, u16, u32, u64, u128, usize } impl ExactSize for VarUint248 { #[inline] - fn exact_size(&self) -> CellSliceSize { - CellSliceSize { + fn exact_size(&self) -> Size { + Size { bits: self.bit_len().unwrap_or_default(), refs: 0, } diff --git a/src/prelude.rs b/src/prelude.rs index d3ce76b6..f17f8f0c 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -5,8 +5,8 @@ pub use crate::boc::{Boc, BocRepr}; pub use crate::cell::{ Cell, CellBuilder, CellContext, CellFamily, CellImpl, CellSlice, CellSliceParts, - CellSliceRange, CellSliceSize, CellType, DynCell, EquivalentRepr, ExactSize, HashBytes, Load, - Store, UsageTree, UsageTreeMode, + CellSliceRange, CellType, DynCell, EquivalentRepr, ExactSize, HashBytes, Load, Size, Store, + UsageTree, UsageTreeMode, }; pub use crate::dict::{AugDict, Dict, RawDict}; diff --git a/src/util.rs b/src/util.rs index 4a5f75fc..9a72f067 100644 --- a/src/util.rs +++ b/src/util.rs @@ -104,6 +104,15 @@ impl ArrayVec { /// Ensure that provided length is small enough. const _ASSERT_LEN: () = assert!(N <= u8::MAX as usize); + /// Returns an empty vector. + pub const fn new() -> Self { + Self { + // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. + inner: unsafe { MaybeUninit::<[MaybeUninit; N]>::uninit().assume_init() }, + len: 0, + } + } + /// Returns the number of elements in the vector, also referred to as its ‘length’. #[inline] pub const fn len(&self) -> usize { @@ -157,11 +166,7 @@ impl ArrayVec { impl Default for ArrayVec { #[inline] fn default() -> Self { - Self { - // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. - inner: unsafe { MaybeUninit::<[MaybeUninit; N]>::uninit().assume_init() }, - len: 0, - } + Self::new() } } From e81950338d7b438a2b01e862dc1cbc4fae22fa0b Mon Sep 17 00:00:00 2001 From: Ivan Kalinin Date: Mon, 12 Aug 2024 15:19:36 +0200 Subject: [PATCH 2/2] feat: add `is_data_prefix_of` and `is_data_suffix_of` to slice --- src/cell/slice.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/src/cell/slice.rs b/src/cell/slice.rs index f72eb617..b634b304 100644 --- a/src/cell/slice.rs +++ b/src/cell/slice.rs @@ -752,6 +752,34 @@ impl<'a> CellSlice<'a> { } } + /// Returns `true` if this slice data is a prefix of the other slice data. + pub fn is_data_prefix_of(&self, other: &Self) -> Result { + let bits = self.size_bits(); + if bits > other.size_bits() { + return Ok(false); + } + + let mut other = other.clone(); + let ok = other.only_first(bits, 0).is_ok(); + debug_assert!(ok); + + Ok(ok!(self.lex_cmp(&other)).is_eq()) + } + + /// Returns `true` if this slice data is a suffix of the other slice data. + pub fn is_data_suffix_of(&self, other: &Self) -> Result { + let bits = self.size_bits(); + if bits > other.size_bits() { + return Ok(false); + } + + let mut other = other.clone(); + let ok = other.only_last(bits, 0).is_ok(); + debug_assert!(ok); + + Ok(ok!(self.lex_cmp(&other)).is_eq()) + } + /// Returns a subslice with the data prefix removed. /// /// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. @@ -1959,4 +1987,102 @@ mod tests { Ok(()) } + + #[test] + fn is_prefix_of() -> anyhow::Result<()> { + let left = build_cell(|b| b.store_u64(0xabcdef1234567890)); + let right = build_cell(|b| b.store_u64(0xabcdef0000000000)); + + // Not a prefix + { + let left = left.as_slice()?; + let right = right.as_slice()?; + assert!(!right.is_data_prefix_of(&left).unwrap()); + } + + // Aligned prefix + { + let left = left.as_slice()?; + let mut right = right.as_slice()?; + right.only_first(24, 0)?; + assert!(right.is_data_prefix_of(&left).unwrap()); + } + + // Shifted prefix + { + let mut left = left.as_slice()?; + left.skip_first(3, 0)?; + + let mut right = right.as_slice()?; + right.skip_first(3, 0)?; + right.only_first(21, 0)?; + + assert!(right.is_data_prefix_of(&left).unwrap()); + } + + // Empty prefix + { + let left = left.as_slice()?; + let right = Cell::empty_cell_ref().as_slice()?; + assert!(right.is_data_prefix_of(&left).unwrap()); + } + + // Not as prefix of an empty prefix + { + let left = Cell::empty_cell_ref().as_slice()?; + let right = right.as_slice()?; + assert!(!right.is_data_prefix_of(&left).unwrap()); + } + + Ok(()) + } + + #[test] + fn is_suffix_of() -> anyhow::Result<()> { + let left = build_cell(|b| b.store_u64(0xabcdef1234567890)); + let right = build_cell(|b| b.store_u64(0x0000001234567890)); + + // Not a suffix + { + let left = left.as_slice()?; + let right = right.as_slice()?; + assert!(!right.is_data_suffix_of(&left).unwrap()); + } + + // Aligned suffix + { + let left = left.as_slice()?; + let mut right = right.as_slice()?; + right.only_last(40, 0)?; + assert!(right.is_data_suffix_of(&left).unwrap()); + } + + // Shifted suffix + { + let mut left = left.as_slice()?; + left.skip_last(3, 0)?; + + let mut right = right.as_slice()?; + right.skip_last(3, 0)?; + right.only_last(37, 0)?; + + assert!(right.is_data_suffix_of(&left).unwrap()); + } + + // Empty suffix + { + let left = left.as_slice()?; + let right = Cell::empty_cell_ref().as_slice()?; + assert!(right.is_data_suffix_of(&left).unwrap()); + } + + // Not as suffix of an empty suffix + { + let left = Cell::empty_cell_ref().as_slice()?; + let right = right.as_slice()?; + assert!(!right.is_data_suffix_of(&left).unwrap()); + } + + Ok(()) + } }