diff --git a/src/boc/mod.rs b/src/boc/mod.rs index 168fe5b2..5688d313 100644 --- a/src/boc/mod.rs +++ b/src/boc/mod.rs @@ -1,7 +1,5 @@ //! BOC (Bag Of Cells) implementation. -use std::borrow::Borrow; - use crate::cell::{Cell, CellBuilder, DefaultFinalizer, DynCell, Finalizer, Load, Store}; /// BOC decoder implementation. @@ -55,7 +53,7 @@ impl Boc { #[cfg(any(feature = "base64", test))] pub fn encode_base64(cell: T) -> String where - T: Borrow, + T: AsRef, { crate::util::encode_base64(Self::encode(cell)) } @@ -63,21 +61,21 @@ impl Boc { /// Encodes the specified cell tree as BOC. pub fn encode(cell: T) -> Vec where - T: Borrow, + T: AsRef, { fn encode_impl(cell: &DynCell) -> Vec { let mut result = Vec::new(); ser::BocHeader::::new(cell).encode(&mut result); result } - encode_impl(cell.borrow()) + encode_impl(cell.as_ref()) } /// Encodes a pair of cell trees as BOC. pub fn encode_pair((cell1, cell2): (T1, T2)) -> Vec where - T1: Borrow, - T2: Borrow, + T1: AsRef, + T2: AsRef, { fn encode_pair_impl(cell1: &DynCell, cell2: &DynCell) -> Vec { let mut result = Vec::new(); @@ -86,7 +84,7 @@ impl Boc { encoder.encode(&mut result); result } - encode_pair_impl(cell1.borrow(), cell2.borrow()) + encode_pair_impl(cell1.as_ref(), cell2.as_ref()) } /// Decodes a `base64` encoded BOC into a cell tree diff --git a/src/cell/builder.rs b/src/cell/builder.rs index f928e701..8a143712 100644 --- a/src/cell/builder.rs +++ b/src/cell/builder.rs @@ -1,4 +1,3 @@ -use std::borrow::Borrow; use std::mem::MaybeUninit; use std::rc::Rc; use std::sync::Arc; @@ -574,7 +573,7 @@ impl CellBuilder { #[inline] pub fn store_cell_data(&mut self, value: T) -> Result<(), Error> where - T: Borrow, + T: AsRef, { fn store_cell_data_impl(builder: &mut CellBuilder, value: &DynCell) -> Result<(), Error> { store_raw( @@ -584,7 +583,7 @@ impl CellBuilder { value.bit_len(), ) } - store_cell_data_impl(self, value.borrow()) + store_cell_data_impl(self, value.as_ref()) } /// Tries to store the remaining slice data in the cell, @@ -592,7 +591,7 @@ impl CellBuilder { #[inline] pub fn store_slice_data<'a, T>(&mut self, value: T) -> Result<(), Error> where - T: Borrow>, + T: AsRef>, { fn store_slice_data_impl( builder: &mut CellBuilder, @@ -609,7 +608,7 @@ impl CellBuilder { Err(Error::CellOverflow) } } - store_slice_data_impl(self, value.borrow()) + store_slice_data_impl(self, value.as_ref()) } /// Tries to prepend bytes to the cell data (but only the specified number of bits), @@ -764,7 +763,7 @@ impl CellBuilder { #[inline] pub fn store_slice<'a, T>(&mut self, value: T) -> Result<(), Error> where - T: Borrow>, + T: AsRef>, { fn store_slice_impl(builder: &mut CellBuilder, value: &CellSlice<'_>) -> Result<(), Error> { if builder.bit_len + value.remaining_bits() <= MAX_BIT_LEN @@ -779,7 +778,7 @@ impl CellBuilder { Err(Error::CellOverflow) } } - store_slice_impl(self, value.borrow()) + store_slice_impl(self, value.as_ref()) } /// Tries to build a new cell using the specified finalizer. @@ -873,7 +872,7 @@ impl CellBuilder { /// Returns an object which will display data as a bitstring /// with a termination bit. - pub fn display_data(&self) -> impl std::fmt::Display + '_ { + pub fn display_data(&self) -> impl std::fmt::Display + std::fmt::Binary + '_ { struct DisplayData<'a>(&'a CellBuilder); impl std::fmt::Display for DisplayData<'_> { @@ -888,6 +887,18 @@ impl CellBuilder { } } + impl std::fmt::Binary for DisplayData<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Binary::fmt( + &Bitstring { + bytes: &self.0.data, + bit_len: self.0.bit_len, + }, + f, + ) + } + } + DisplayData(self) } } diff --git a/src/cell/mod.rs b/src/cell/mod.rs index 15b8815b..13424b71 100644 --- a/src/cell/mod.rs +++ b/src/cell/mod.rs @@ -72,6 +72,20 @@ pub type DynCell = dyn CellImpl; #[cfg(feature = "sync")] pub type DynCell = dyn CellImpl + Send + Sync; +impl AsRef for DynCell { + #[inline(always)] + fn as_ref(&self) -> &Self { + self + } +} + +impl AsMut for DynCell { + #[inline(always)] + fn as_mut(&mut self) -> &mut Self { + self + } +} + /// Represents the interface of a well-formed cell. /// /// Since all basic operations are implements via dynamic dispatch, @@ -254,7 +268,7 @@ impl DynCell { /// Returns an object which will display cell data as a bitstring /// with a termination bit. #[inline] - pub fn display_data(&self) -> impl std::fmt::Display + '_ { + pub fn display_data(&self) -> impl std::fmt::Display + std::fmt::Binary + '_ { struct DisplayData<'a>(&'a DynCell); impl std::fmt::Display for DisplayData<'_> { @@ -269,6 +283,18 @@ impl DynCell { } } + impl std::fmt::Binary for DisplayData<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Binary::fmt( + &Bitstring { + bytes: self.0.data(), + bit_len: self.0.bit_len(), + }, + f, + ) + } + } + DisplayData(self) } diff --git a/src/cell/slice.rs b/src/cell/slice.rs index 74b5d2a3..b8de02d1 100644 --- a/src/cell/slice.rs +++ b/src/cell/slice.rs @@ -196,7 +196,7 @@ impl CellSliceRange { #[inline] pub fn apply(self, cell: &T) -> Result, Error> where - T: AsRef, + T: AsRef + ?Sized, { fn apply_impl(range: CellSliceRange, cell: &DynCell) -> Result, Error> { // Handle pruned branch access @@ -230,7 +230,7 @@ impl CellSliceRange { /// - range is in cell bounds pub unsafe fn apply_unchecked(self, cell: &T) -> CellSlice<'_> where - T: AsRef, + T: AsRef + ?Sized, { CellSlice { range: self, @@ -324,6 +324,20 @@ impl<'a> Clone for CellSlice<'a> { impl<'a> Copy for CellSlice<'a> {} +impl<'a> AsRef> for CellSlice<'a> { + #[inline] + fn as_ref(&self) -> &CellSlice<'a> { + self + } +} + +impl<'a> AsMut> for CellSlice<'a> { + #[inline] + fn as_mut(&mut self) -> &mut CellSlice<'a> { + self + } +} + impl<'a> CellSlice<'a> { /// Constructs a new cell slice from the specified cell. /// Returns an error if the cell is pruned. @@ -1419,25 +1433,31 @@ impl<'a> CellSlice<'a> { /// Returns an object which will display data as a bitstring /// with a termination bit. - pub fn display_data<'b: 'a>(&'b self) -> impl std::fmt::Display + 'b { + pub fn display_data<'b: 'a>(&'b self) -> impl std::fmt::Display + std::fmt::Binary + 'b { + fn make_bitstring<'b: 'a, 'a>( + s: &'b CellSlice<'a>, + bytes: &'b mut [u8; 128], + ) -> Result, std::fmt::Error> { + let bit_len = s.remaining_bits(); + if s.get_raw(0, bytes, bit_len).is_err() { + return Err(std::fmt::Error); + } + Ok(Bitstring { bytes, bit_len }) + } + struct DisplayData<'b, 'a>(&'b CellSlice<'a>); impl<'b: 'a, 'a> std::fmt::Display for DisplayData<'b, 'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let s = self.0; - let bit_len = s.remaining_bits(); let mut bytes = [0u8; 128]; - if s.get_raw(0, &mut bytes, bit_len).is_err() { - return Err(std::fmt::Error); - } + std::fmt::Display::fmt(&ok!(make_bitstring(self.0, &mut bytes)), f) + } + } - std::fmt::Display::fmt( - &Bitstring { - bytes: &bytes, - bit_len, - }, - f, - ) + impl<'b: 'a, 'a> std::fmt::Binary for DisplayData<'b, 'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut bytes = [0u8; 128]; + std::fmt::Binary::fmt(&ok!(make_bitstring(self.0, &mut bytes)), f) } } diff --git a/src/dict/mod.rs b/src/dict/mod.rs index af1c0ba8..568a926a 100644 --- a/src/dict/mod.rs +++ b/src/dict/mod.rs @@ -2,7 +2,6 @@ use crate::cell::*; use crate::error::Error; -use crate::util::unlikely; pub use aug::*; pub use raw::*; @@ -128,20 +127,10 @@ pub fn dict_remove_owned( key.try_advance(lcp.remaining_bits(), 0); // Load the next branch - let next_branch = match key.load_bit() { - Ok(false) => Branch::Left, - Ok(true) => Branch::Right, - Err(e) => return Err(e), - }; + let next_branch = Branch::from(ok!(key.load_bit())); let child = match data.reference(next_branch as u8) { - Some(child) => { - // Handle pruned branch access - if unlikely(child.descriptor().is_pruned_branch()) { - return Err(Error::PrunedBranchAccess); - } - child - } + Some(child) => child, None => return Err(Error::CellUnderflow), }; @@ -194,26 +183,7 @@ pub fn dict_remove_owned( return Ok((None, Some((root.clone(), removed)))); }; - // Rebuild the tree starting from leaves - while let Some(last) = stack.pop() { - // Load the opposite branch - let (left, right) = match last.next_branch { - Branch::Left => match last.data.reference_cloned(1) { - Some(cell) => (leaf, cell), - None => return Err(Error::CellUnderflow), - }, - Branch::Right => match last.data.reference_cloned(0) { - Some(cell) => (cell, leaf), - None => return Err(Error::CellUnderflow), - }, - }; - - let mut builder = CellBuilder::new(); - ok!(builder.store_cell_data(last.data)); - ok!(builder.store_reference(left)); - ok!(builder.store_reference(right)); - leaf = ok!(builder.build_ext(finalizer)); - } + leaf = ok!(rebuild_dict_from_stack(stack, leaf, finalizer)); Ok((Some(leaf), Some(removed))) } @@ -331,19 +301,12 @@ pub fn dict_insert( // Load the next branch let next_branch = match key.load_bit() { - Ok(false) => Branch::Left, - Ok(true) => Branch::Right, + Ok(bit) => Branch::from(bit), Err(e) => return Err(e), }; let child = match data.reference(next_branch as u8) { - Some(child) => { - // Handle pruned branch access - if unlikely(child.descriptor().is_pruned_branch()) { - return Err(Error::PrunedBranchAccess); - } - child - } + Some(child) => child, None => return Err(Error::CellUnderflow), }; @@ -358,26 +321,7 @@ pub fn dict_insert( } }; - // Rebuild the tree starting from leaves - while let Some(last) = stack.pop() { - // Load the opposite branch - let (left, right) = match last.next_branch { - Branch::Left => match last.data.reference_cloned(1) { - Some(cell) => (leaf, cell), - None => return Err(Error::CellUnderflow), - }, - Branch::Right => match last.data.reference_cloned(0) { - Some(cell) => (cell, leaf), - None => return Err(Error::CellUnderflow), - }, - }; - - let mut builder = CellBuilder::new(); - ok!(builder.store_cell_data(last.data)); - ok!(builder.store_reference(left)); - ok!(builder.store_reference(right)); - leaf = ok!(builder.build_ext(finalizer)); - } + leaf = ok!(rebuild_dict_from_stack(stack, leaf, finalizer)); Ok(Some(leaf)) } @@ -487,6 +431,195 @@ pub fn dict_get_owned( }) } +/// Returns cell slice parts of the value corresponding to the key. +pub fn dict_find_owned( + root: &Option, + key_bit_len: u16, + mut key: CellSlice<'_>, + towards: DictBound, + inclusive: bool, + signed: bool, +) -> Result, Error> { + if key.remaining_bits() != key_bit_len { + return Err(Error::CellUnderflow); + } + + enum Leaf { + Value(CellSliceRange), + Divergence(Branch), + } + + let Some(root) = root else { + return Ok(None); + }; + + let mut original_key_range = key.range(); + let mut result_key = CellBuilder::new(); + + let mut data = root.as_ref(); + let mut stack = Vec::<(Segment, u16)>::new(); + let mut prev = None; + + // Try to find the required leaf + let value_range = 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())); + + // 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()) { + // 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() { + // Stop searching for the value with the first divergent bit + break Leaf::Divergence(Branch::from(ok!(key.get_bit(lcp_len)))); + } + + // The key contains the entire prefix, but there are still some bits left. + // Fail fast if there are not enough references in the fork + if data.reference_count() != 2 { + return Err(Error::CellUnderflow); + } + + // Remove the LCP from the key + key.try_advance(lcp.remaining_bits(), 0); + + // Load the next branch + let next_branch = Branch::from(ok!(key.load_bit())); + + let child = match data.reference(next_branch as u8) { + Some(child) => child, + None => return Err(Error::CellUnderflow), + }; + + // Push an intermediate edge to the stack + stack.push((Segment { data, next_branch }, key.remaining_bits())); + prev = Some((data, next_branch)); + data = child; + } + std::cmp::Ordering::Greater => { + debug_assert!(false, "LCP of prefix and key can't be greater than key"); + unsafe { std::hint::unreachable_unchecked() }; + } + } + }; + + // Return a value with the exact key + if inclusive { + if let Leaf::Value(value_range) = value_range { + let cell = match stack.last() { + Some((Segment { data, next_branch }, _)) => { + match data.reference_cloned(*next_branch as u8) { + Some(cell) => cell, + None => return Err(Error::CellUnderflow), + } + } + None => root.clone(), + }; + + let original_key = ok!(original_key_range.apply(key.cell())); + ok!(result_key.store_slice_data(original_key)); + + return Ok(Some((result_key, (cell, value_range)))); + } + } + + // Rewind back to the divergent branch + let rev_direction = towards.into_branch().reversed(); + let (mut data, mut remaining_bits, first_branch) = 'fork: { + 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 prefix_len = key_bit_len - remaining_bits; + original_key_range = original_key_range.get_prefix(prefix_len, 0); + break 'fork (data, remaining_bits, None); + } + } + + while let Some((Segment { data, next_branch }, remaining_bits)) = stack.pop() { + let prefix_len = key_bit_len - remaining_bits; + let signed_root = signed && prefix_len == 1; + + // Pop until the first diverged branch + let first_branch = if signed_root && next_branch != rev_direction { + rev_direction + } else if !signed_root && next_branch == rev_direction { + rev_direction.reversed() + } else { + continue; + }; + + // Remove the last bit from the prefix (we are chaning it to the opposite) + original_key_range = original_key_range.get_prefix(prefix_len - 1, 0); + prev = Some((data, next_branch)); + break 'fork (data, remaining_bits, Some(first_branch)); + } + // There is no next/prev element if rewind consumed all stack + return Ok(None); + }; + + // Store the longest suitable prefix + let original_key = ok!(original_key_range.apply(key.cell())); + ok!(result_key.store_slice_data(original_key)); + + // Prepare the node to start the final search + if let Some(branch) = first_branch { + ok!(result_key.store_bit(branch.into_bit())); + let Some(child) = data.reference(branch as u8) else { + return Err(Error::CellUnderflow); + }; + prev = Some((data, branch)); + data = child; + } + + // Try to find the required leaf + let value_range = loop { + let mut remaining_data = ok!(data.as_slice()); + + // Read the key part written in the current edge + let prefix = &ok!(read_label(&mut remaining_data, remaining_bits)); + if !prefix.is_data_empty() { + ok!(result_key.store_slice_data(prefix)); + } + + match remaining_bits.checked_sub(prefix.remaining_bits()) { + Some(0) => break remaining_data.range(), + Some(remaining) => { + if remaining_data.remaining_refs() < 2 { + return Err(Error::CellUnderflow); + } + remaining_bits = remaining - 1; + } + None => return Err(Error::CellUnderflow), + } + + ok!(result_key.store_bit(rev_direction.into_bit())); + + let Some(child) = data.reference(rev_direction as u8) else { + return Err(Error::CellUnderflow); + }; + prev = Some((data, rev_direction)); + data = child; + }; + + let cell = match prev { + Some((prev, next_branch)) => match prev.reference_cloned(next_branch as u8) { + Some(cell) => cell, + None => return Err(Error::CellUnderflow), + }, + None => root.clone(), + }; + + Ok(Some((result_key, (cell, value_range)))) +} + /// Finds the specified dict bound and returns a key and a value corresponding to the key. pub fn dict_find_bound<'a: 'b, 'b>( root: &'a Option, @@ -617,10 +750,9 @@ pub fn dict_remove_bound_owned( let mut remaining_data = ok!(data.as_slice()); // Read the key part written in the current edge - let prefix = ok!(read_label(&mut remaining_data, key_bit_len)); - #[allow(clippy::needless_borrow)] + let prefix = &ok!(read_label(&mut remaining_data, key_bit_len)); if !prefix.is_data_empty() { - ok!(key.store_slice_data(&prefix)); + ok!(key.store_slice_data(prefix)); } match key_bit_len.checked_sub(prefix.remaining_bits()) { @@ -635,18 +767,11 @@ pub fn dict_remove_bound_owned( None => return Err(Error::CellUnderflow), }; - let next_branch = bound.update_direction(&prefix, signed, &mut direction); + let next_branch = bound.update_direction(prefix, signed, &mut direction); ok!(key.store_bit(next_branch.into_bit())); - let child = match data.reference(next_branch as u8) { - Some(child) => { - // Handle pruned branch access - if unlikely(child.descriptor().is_pruned_branch()) { - return Err(Error::PrunedBranchAccess); - } - child - } - None => return Err(Error::CellUnderflow), + let Some(child) = data.reference(next_branch as u8) else { + return Err(Error::CellUnderflow); }; // Push an intermediate edge to the stack @@ -692,26 +817,7 @@ pub fn dict_remove_bound_owned( return Ok((None, Some((key, (root.clone(), removed))))); }; - // Rebuild the tree starting from leaves - while let Some(last) = stack.pop() { - // Load the opposite branch - let (left, right) = match last.next_branch { - Branch::Left => match last.data.reference_cloned(1) { - Some(cell) => (leaf, cell), - None => return Err(Error::CellUnderflow), - }, - Branch::Right => match last.data.reference_cloned(0) { - Some(cell) => (cell, leaf), - None => return Err(Error::CellUnderflow), - }, - }; - - let mut builder = CellBuilder::new(); - ok!(builder.store_cell_data(last.data)); - ok!(builder.store_reference(left)); - ok!(builder.store_reference(right)); - leaf = ok!(builder.build_ext(finalizer)); - } + leaf = ok!(rebuild_dict_from_stack(stack, leaf, finalizer)); Ok((Some(leaf), Some((key, removed)))) } @@ -783,6 +889,35 @@ pub fn dict_load_from_root( builder.build_ext(finalizer) } +fn rebuild_dict_from_stack( + mut segments: Vec>, + mut leaf: Cell, + finalizer: &mut dyn Finalizer, +) -> Result { + // Rebuild the tree starting from leaves + while let Some(last) = segments.pop() { + // Load the opposite branch + let (left, right) = match last.next_branch { + Branch::Left => match last.data.reference_cloned(1) { + Some(cell) => (leaf, cell), + None => return Err(Error::CellUnderflow), + }, + Branch::Right => match last.data.reference_cloned(0) { + Some(cell) => (cell, leaf), + None => return Err(Error::CellUnderflow), + }, + }; + + let mut builder = CellBuilder::new(); + ok!(builder.store_cell_data(last.data)); + ok!(builder.store_reference(left)); + ok!(builder.store_reference(right)); + leaf = ok!(builder.build_ext(finalizer)); + } + + Ok(leaf) +} + #[derive(Clone, Copy)] struct Segment<'a> { data: &'a DynCell, @@ -864,7 +999,7 @@ fn write_label_parts( fn read_label<'a>(label: &mut CellSlice<'a>, key_bit_len: u16) -> Result, Error> { let bits_for_len = (16 - key_bit_len.leading_zeros()) as u16; - if label.is_data_empty() && bits_for_len == 0 { + if bits_for_len == 0 && label.is_data_empty() { Ok(label.get_prefix(0, 0)) } else if !ok!(label.load_bit()) { read_hml_short(label) @@ -950,7 +1085,7 @@ fn serialize_entry(entry: &T, finalizer: &mut dyn Finalizer) -> Result builder.build_ext(finalizer) } -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] enum Branch { // Branch for a key part that starts with bit 0 Left = 0, @@ -971,6 +1106,16 @@ impl Branch { } } +impl From for Branch { + fn from(value: bool) -> Self { + if value { + Self::Right + } else { + Self::Left + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/dict/raw.rs b/src/dict/raw.rs index b0d0a1ee..1dc363e2 100644 --- a/src/dict/raw.rs +++ b/src/dict/raw.rs @@ -3,7 +3,7 @@ use crate::error::Error; use crate::util::{unlikely, IterStatus}; use super::{ - dict_find_bound, dict_find_bound_owned, dict_get, dict_get_owned, dict_insert, + dict_find_bound, dict_find_bound_owned, dict_find_owned, dict_get, dict_get_owned, dict_insert, dict_load_from_root, dict_remove_bound_owned, dict_remove_owned, read_label, DictBound, DictOwnedEntry, SetMode, }; @@ -133,6 +133,46 @@ impl RawDict { dict_get(&self.0, N, key) } + /// Computes the minimal key in dictionary that is lexicographically greater than `key`, + /// and returns it along with associated value as cell slice parts. + pub fn get_next_owned( + &self, + key: CellSlice<'_>, + signed: bool, + ) -> Result, Error> { + dict_find_owned(&self.0, N, key, DictBound::Max, false, signed) + } + + /// Computes the maximal key in dictionary that is lexicographically smaller than `key`, + /// and returns it along with associated value as cell slice parts. + pub fn get_prev_owned( + &self, + key: CellSlice<'_>, + signed: bool, + ) -> Result, Error> { + dict_find_owned(&self.0, N, key, DictBound::Min, false, signed) + } + + /// Computes the minimal key in dictionary that is lexicographically greater than `key`, + /// and returns it along with associated value as cell slice parts. + pub fn get_or_next_owned( + &self, + key: CellSlice<'_>, + signed: bool, + ) -> Result, Error> { + dict_find_owned(&self.0, N, key, DictBound::Max, true, signed) + } + + /// Computes the maximal key in dictionary that is lexicographically smaller than `key`, + /// and returns it along with associated value as cell slice parts. + pub fn get_or_prev_owned( + &self, + key: CellSlice<'_>, + signed: bool, + ) -> Result, Error> { + dict_find_owned(&self.0, N, key, DictBound::Min, true, signed) + } + /// Returns cell slice parts of the value corresponding to the key. pub fn get_owned(&self, key: CellSlice<'_>) -> Result, Error> { dict_get_owned(&self.0, N, key) diff --git a/src/dict/typed.rs b/src/dict/typed.rs index ab91fe52..d1aa3e8c 100644 --- a/src/dict/typed.rs +++ b/src/dict/typed.rs @@ -7,8 +7,8 @@ use crate::error::Error; use crate::util::*; use super::{ - dict_find_bound, dict_get, dict_insert, dict_load_from_root, serialize_entry, DictBound, - DictKey, SetMode, + dict_find_bound, dict_find_owned, dict_get, dict_insert, dict_load_from_root, serialize_entry, + DictBound, DictKey, SetMode, }; use super::{dict_remove_bound_owned, raw::*}; @@ -321,6 +321,183 @@ where pub fn keys(&'_ self) -> Keys<'_, K> { Keys::new(&self.root) } + + /// Computes the minimal key in dictionary that is lexicographically greater than `key`, + /// and returns it along with associated value as cell slice parts. + /// + /// Use [`get_next_ext`] if you need to use a custom finalizer. + /// + /// [`get_next_ext`]: Dict::get_next_ext + #[inline] + pub fn get_next(&self, key: Q, signed: bool) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + self.get_next_ext(key, signed, &mut Cell::default_finalizer()) + } + + /// Computes the maximal key in dictionary that is lexicographically smaller than `key`, + /// and returns it along with associated value as cell slice parts. + /// + /// Use [`get_prev_ext`] if you need to use a custom finalizer. + /// + /// [`get_prev_ext`]: Dict::get_prev_ext + #[inline] + pub fn get_prev(&self, key: Q, signed: bool) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + self.get_prev_ext(key, signed, &mut Cell::default_finalizer()) + } + + /// Computes the minimal key in dictionary that is lexicographically greater than `key`, + /// and returns it along with associated value as cell slice parts. + /// + /// Use [`get_or_next_ext`] if you need to use a custom finalizer. + /// + /// [`get_or_next_ext`]: Dict::get_or_next_ext + #[inline] + pub fn get_or_next(&self, key: Q, signed: bool) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + self.get_or_next_ext(key, signed, &mut Cell::default_finalizer()) + } + + /// Computes the maximal key in dictionary that is lexicographically smaller than `key`, + /// and returns it along with associated value as cell slice parts. + /// + /// Use [`get_or_prev_ext`] if you need to use a custom finalizer. + /// + /// [`get_or_prev_ext`]: Dict::get_or_prev_ext + #[inline] + pub fn get_or_prev(&self, key: Q, signed: bool) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + self.get_or_prev_ext(key, signed, &mut Cell::default_finalizer()) + } + + /// Computes the minimal key in dictionary that is lexicographically greater than `key`, + /// and returns it along with associated value as cell slice parts. + #[inline] + pub fn get_next_ext( + &self, + key: Q, + signed: bool, + finalizer: &mut dyn Finalizer, + ) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + self.find_ext(key, DictBound::Max, false, signed, finalizer) + } + + /// Computes the maximal key in dictionary that is lexicographically smaller than `key`, + /// and returns it along with associated value as cell slice parts. + #[inline] + pub fn get_prev_ext( + &self, + key: Q, + signed: bool, + finalizer: &mut dyn Finalizer, + ) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + self.find_ext(key, DictBound::Min, false, signed, finalizer) + } + + /// Computes the minimal key in dictionary that is lexicographically greater than `key`, + /// and returns it along with associated value as cell slice parts. + #[inline] + pub fn get_or_next_ext( + &self, + key: Q, + signed: bool, + finalizer: &mut dyn Finalizer, + ) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + self.find_ext(key, DictBound::Max, true, signed, finalizer) + } + + /// Computes the maximal key in dictionary that is lexicographically smaller than `key`, + /// and returns it along with associated value as cell slice parts. + #[inline] + pub fn get_or_prev_ext( + &self, + key: Q, + signed: bool, + finalizer: &mut dyn Finalizer, + ) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + self.find_ext(key, DictBound::Min, true, signed, finalizer) + } + + #[inline] + fn find_ext( + &self, + key: Q, + towards: DictBound, + inclusive: bool, + signed: bool, + finalizer: &mut dyn Finalizer, + ) -> Result, Error> + where + Q: Borrow, + for<'a> V: Load<'a>, + { + fn find_ext_impl( + root: &Option, + key: &K, + towards: DictBound, + inclusive: bool, + signed: bool, + finalizer: &mut dyn Finalizer, + ) -> Result, Error> + where + K: DictKey + Store, + for<'a> V: Load<'a>, + { + let key = ok!(serialize_entry(key, finalizer)); + let Some((key, (cell, range))) = ok!(dict_find_owned( + root, + K::BITS, + ok!(key.as_slice()), + towards, + inclusive, + signed + )) else { + return Ok(None); + }; + let value = &mut ok!(range.apply(&cell)); + + match K::from_raw_data(key.raw_data()) { + Some(key) => Ok(Some((key, ok!(V::load_from(value))))), + None => Err(Error::CellUnderflow), + } + } + find_ext_impl( + &self.root, + key.borrow(), + towards, + inclusive, + signed, + finalizer, + ) + } } impl Dict @@ -821,6 +998,13 @@ mod tests { assert_eq!(dict.get_min(true).unwrap(), Some((-10, true))); assert_eq!(dict.get_max(true).unwrap(), Some((10, false))); + + let mut dict = Dict::::new(); + for i in 1..=3 { + dict.set(i, 0xff).unwrap(); + } + assert_eq!(dict.get_min(false).unwrap(), Some((1, 0xff))); + assert_eq!(dict.get_max(false).unwrap(), Some((3, 0xff))); } #[test] @@ -958,6 +1142,102 @@ mod tests { } } + #[test] + fn dict_next_prev_unsigned() { + let mut dict = Dict::::new(); + + for i in 0..=10 { + dict.set(i, i).unwrap(); + } + + for i in 20..=30 { + dict.set(i, i).unwrap(); + } + + println!("{}", BocRepr::encode_base64(&dict).unwrap()); + + assert_eq!(dict.get_prev(0, false).unwrap(), None); + assert_eq!(dict.get_or_prev(0, false).unwrap(), Some((0, 0))); + + assert_eq!(dict.get_next(30, false).unwrap(), None); + assert_eq!(dict.get_or_next(30, false).unwrap(), Some((30, 30))); + + assert_eq!(dict.get_prev(15, false).unwrap(), Some((10, 10))); + assert_eq!(dict.get_or_prev(15, false).unwrap(), Some((10, 10))); + + assert_eq!(dict.get_next(15, false).unwrap(), Some((20, 20))); + assert_eq!(dict.get_or_next(15, false).unwrap(), Some((20, 20))); + + assert_eq!(dict.get_next(19, false).unwrap(), Some((20, 20))); + assert_eq!(dict.get_or_next(19, false).unwrap(), Some((20, 20))); + + assert_eq!(dict.get_prev(20, false).unwrap(), Some((10, 10))); + assert_eq!(dict.get_or_prev(20, false).unwrap(), Some((20, 20))); + + assert_eq!(dict.get_next(100, false).unwrap(), None); + assert_eq!(dict.get_or_next(100, false).unwrap(), None); + + assert_eq!(dict.get_prev(100, false).unwrap(), Some((30, 30))); + assert_eq!(dict.get_or_prev(100, false).unwrap(), Some((30, 30))); + } + + #[test] + fn dict_next_prev_signed() { + let mut dict = Dict::::new(); + + for i in -20..=-10 { + dict.set(i, i).unwrap(); + } + + assert_eq!(dict.get_prev(-20, true).unwrap(), None); + assert_eq!(dict.get_or_prev(-20, true).unwrap(), Some((-20, -20))); + + assert_eq!(dict.get_next(-10, true).unwrap(), None); + assert_eq!(dict.get_or_next(-10, true).unwrap(), Some((-10, -10))); + + for i in 10..=20 { + dict.set(i, i).unwrap(); + } + + println!("{}", BocRepr::encode_base64(&dict).unwrap()); + + assert_eq!(dict.get_next(-100, true).unwrap(), Some((-20, -20))); + assert_eq!(dict.get_or_next(-100, true).unwrap(), Some((-20, -20))); + + assert_eq!(dict.get_prev(-100, true).unwrap(), None); + assert_eq!(dict.get_or_prev(-100, true).unwrap(), None); + + assert_eq!(dict.get_prev(-20, true).unwrap(), None); + assert_eq!(dict.get_or_prev(-20, true).unwrap(), Some((-20, -20))); + + assert_eq!(dict.get_next(20, true).unwrap(), None); + assert_eq!(dict.get_or_next(20, true).unwrap(), Some((20, 20))); + + assert_eq!(dict.get_prev(-10, true).unwrap(), Some((-11, -11))); + assert_eq!(dict.get_or_prev(-10, true).unwrap(), Some((-10, -10))); + + assert_eq!(dict.get_next(-10, true).unwrap(), Some((10, 10))); + assert_eq!(dict.get_or_next(-10, true).unwrap(), Some((-10, -10))); + + assert_eq!(dict.get_prev(-9, true).unwrap(), Some((-10, -10))); + assert_eq!(dict.get_or_prev(-9, true).unwrap(), Some((-10, -10))); + + assert_eq!(dict.get_prev(0, true).unwrap(), Some((-10, -10))); + assert_eq!(dict.get_or_prev(0, true).unwrap(), Some((-10, -10))); + + assert_eq!(dict.get_next(0, true).unwrap(), Some((10, 10))); + assert_eq!(dict.get_or_next(0, true).unwrap(), Some((10, 10))); + + assert_eq!(dict.get_prev(10, true).unwrap(), Some((-10, -10))); + assert_eq!(dict.get_or_prev(10, true).unwrap(), Some((10, 10))); + + assert_eq!(dict.get_next(100, true).unwrap(), None); + assert_eq!(dict.get_or_next(100, true).unwrap(), None); + + assert_eq!(dict.get_prev(100, true).unwrap(), Some((20, 20))); + assert_eq!(dict.get_or_prev(100, true).unwrap(), Some((20, 20))); + } + #[test] #[cfg_attr(miri, ignore)] fn big_dict() { diff --git a/src/serde.rs b/src/serde.rs index 9daf85ca..9d461d23 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -21,7 +21,7 @@ impl Boc { pub fn serialize(cell: &T, serializer: S) -> Result where S: Serializer, - T: AsRef, + T: AsRef + ?Sized, { cell.as_ref().serialize(serializer) } diff --git a/src/util.rs b/src/util.rs index 9f6c4540..fd4539e0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -218,6 +218,31 @@ impl std::fmt::Display for Bitstring<'_> { } } +impl std::fmt::Binary for Bitstring<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let bit_len = std::cmp::min(self.bit_len as usize, self.bytes.len() * 8) as u16; + let byte_len = ((bit_len + 7) / 8) as usize; + let bytes = &self.bytes[..byte_len]; + + let rem = (bit_len % 8) as usize; + let (bytes, last_byte) = match bytes.split_last() { + Some((last_byte, bytes)) if rem != 0 => (bytes, Some(*last_byte)), + _ => (bytes, None), + }; + + for byte in bytes { + ok!(write!(f, "{byte:08b}")); + } + + if let Some(mut last_byte) = last_byte { + last_byte >>= 8 - rem; + ok!(write!(f, "{last_byte:0rem$b}")) + } + + Ok(()) + } +} + pub(crate) fn debug_tuple_field1_finish( f: &mut std::fmt::Formatter<'_>, name: &str,