use impl_tools::autoimpl;
use tlb::{
bits::{
bitvec::{order::Msb0, slice::BitSlice, vec::BitVec},
de::BitReaderExt,
ser::BitWriterExt,
},
de::{
args::{r#as::CellDeserializeAsWithArgs, CellDeserializeWithArgs},
CellParser, CellParserError,
},
r#as::{ParseFully, Ref, Same},
ser::{
args::{r#as::CellSerializeAsWithArgs, CellSerializeWithArgs},
CellBuilder, CellBuilderError,
},
Error, ResultExt,
};
use super::hm_label::HmLabel;
#[derive(Debug, Clone)]
#[autoimpl(Deref using self.m)]
#[autoimpl(DerefMut using self.m)]
#[autoimpl(Default where E: Default)]
pub struct HashmapAugE<T, E = ()> {
pub m: HashmapE<T, E>,
pub extra: E,
}
impl<T, AsT, E, AsE> CellSerializeAsWithArgs<HashmapAugE<T, E>> for HashmapAugE<AsT, AsE>
where
AsT: CellSerializeAsWithArgs<T>,
AsT::Args: Clone,
AsE: CellSerializeAsWithArgs<E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
#[inline]
fn store_as_with(
source: &HashmapAugE<T, E>,
builder: &mut CellBuilder,
(n, node_args, extra_args): Self::Args,
) -> Result<(), CellBuilderError> {
builder
.store_as_with::<_, &HashmapE<AsT, AsE>>(&source.m, (n, node_args, extra_args.clone()))?
.store_as_with::<_, &AsE>(&source.extra, extra_args)
.context("extra")?;
Ok(())
}
}
impl<'de, T, AsT, E, AsE> CellDeserializeAsWithArgs<'de, HashmapAugE<T, E>>
for HashmapAugE<AsT, AsE>
where
AsT: CellDeserializeAsWithArgs<'de, T>,
AsT::Args: Clone,
AsE: CellDeserializeAsWithArgs<'de, E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
#[inline]
fn parse_as_with(
parser: &mut CellParser<'de>,
(n, node_args, extra_args): Self::Args,
) -> Result<HashmapAugE<T, E>, CellParserError<'de>> {
Ok(HashmapAugE {
m: parser.parse_as_with::<_, HashmapE<AsT, AsE>>((n, node_args, extra_args.clone()))?,
extra: parser
.parse_as_with::<_, AsE>(extra_args)
.context("extra")?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HashmapE<T, E = ()> {
Empty,
Root(Hashmap<T, E>),
}
impl<T, E> Default for HashmapE<T, E> {
#[inline]
fn default() -> Self {
Self::Empty
}
}
impl<T, E> HashmapE<T, E> {
#[inline]
pub const fn new() -> Self {
Self::Empty
}
#[inline]
pub fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
#[inline]
pub fn len(&self) -> usize {
match self {
Self::Empty => 0,
Self::Root(root) => root.len(),
}
}
#[inline]
pub fn contains_key(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> bool {
match self {
Self::Empty => false,
Self::Root(root) => root.contains_key(key),
}
}
#[inline]
pub fn get(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&T> {
match self {
Self::Empty => None,
Self::Root(root) => root.get(key),
}
}
#[inline]
pub fn get_mut(&mut self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&mut T> {
match self {
Self::Empty => None,
Self::Root(root) => root.get_mut(key),
}
}
}
impl<T, AsT, E, AsE> CellSerializeAsWithArgs<HashmapE<T, E>> for HashmapE<AsT, AsE>
where
AsT: CellSerializeAsWithArgs<T>,
AsT::Args: Clone,
AsE: CellSerializeAsWithArgs<E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
#[inline]
fn store_as_with(
source: &HashmapE<T, E>,
builder: &mut CellBuilder,
args: Self::Args,
) -> Result<(), CellBuilderError> {
match source {
HashmapE::Empty => builder
.pack(false)?,
HashmapE::Root(root) => builder
.pack(true)?
.store_as_with::<_, Ref<&Hashmap<AsT, AsE>>>(root, args)?,
};
Ok(())
}
}
impl<T, E> CellSerializeWithArgs for HashmapE<T, E>
where
T: CellSerializeWithArgs,
T::Args: Clone,
E: CellSerializeWithArgs,
E::Args: Clone,
{
type Args = (u32, T::Args, E::Args);
#[inline]
fn store_with(
&self,
builder: &mut CellBuilder,
args: Self::Args,
) -> Result<(), CellBuilderError> {
builder.store_as_with::<_, Same>(self, args)?;
Ok(())
}
}
impl<'de, T, AsT, E, AsE> CellDeserializeAsWithArgs<'de, HashmapE<T, E>> for HashmapE<AsT, AsE>
where
AsT: CellDeserializeAsWithArgs<'de, T>,
AsT::Args: Clone,
AsE: CellDeserializeAsWithArgs<'de, E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
#[inline]
fn parse_as_with(
parser: &mut CellParser<'de>,
(n, node_args, extra_args): Self::Args,
) -> Result<HashmapE<T, E>, CellParserError<'de>> {
Ok(match parser.unpack()? {
false => HashmapE::Empty,
true => parser
.parse_as_with::<_, Ref<ParseFully<Hashmap<AsT, AsE>>>>((n, node_args, extra_args))
.map(HashmapE::Root)?,
})
}
}
impl<'de, T> CellDeserializeWithArgs<'de> for HashmapE<T>
where
T: CellDeserializeWithArgs<'de>,
T::Args: Clone,
{
type Args = (u32, T::Args);
#[inline]
fn parse_with(
parser: &mut CellParser<'de>,
args: Self::Args,
) -> Result<Self, CellParserError<'de>> {
parser.parse_as_with::<_, Same>(args)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Hashmap<T, E = ()> {
pub(super) prefix: BitVec<u8, Msb0>,
pub(super) node: HashmapAugNode<T, E>,
}
impl<T, E> Hashmap<T, E> {
#[inline]
pub fn new(prefix: impl Into<BitVec<u8, Msb0>>, node: HashmapAugNode<T, E>) -> Self {
Self {
prefix: prefix.into(),
node,
}
}
#[inline]
pub fn prefix(&self) -> &BitSlice<u8, Msb0> {
&self.prefix
}
#[inline]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.node.len()
}
#[inline]
pub fn contains_key(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> bool {
key.as_ref()
.strip_prefix(&self.prefix)
.map_or(false, |key| self.node.contains_key(key))
}
#[inline]
pub fn get(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&T> {
self.node.get(key.as_ref().strip_prefix(&self.prefix)?)
}
#[inline]
pub fn get_mut(&mut self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&mut T> {
self.node.get_mut(key.as_ref().strip_prefix(&self.prefix)?)
}
}
impl<T, AsT, E, AsE> CellSerializeAsWithArgs<Hashmap<T, E>> for Hashmap<AsT, AsE>
where
AsT: CellSerializeAsWithArgs<T>,
AsT::Args: Clone,
AsE: CellSerializeAsWithArgs<E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
fn store_as_with(
source: &Hashmap<T, E>,
builder: &mut CellBuilder,
(n, node_args, extra_args): Self::Args,
) -> Result<(), CellBuilderError> {
builder
.pack_as_with::<_, &HmLabel>(source.prefix.as_bitslice(), n)
.context("label")?
.store_as_with::<_, &HashmapAugNode<AsT, AsE>>(
&source.node,
(
n - source.prefix.len() as u32,
node_args,
extra_args,
),
)
.context("node")?;
Ok(())
}
}
impl<'de, T, AsT, E, AsE> CellDeserializeAsWithArgs<'de, Hashmap<T, E>> for Hashmap<AsT, AsE>
where
AsT: CellDeserializeAsWithArgs<'de, T>,
AsT::Args: Clone,
AsE: CellDeserializeAsWithArgs<'de, E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
#[inline]
fn parse_as_with(
parser: &mut CellParser<'de>,
(n, node_args, extra_args): Self::Args,
) -> Result<Hashmap<T, E>, CellParserError<'de>> {
let prefix: BitVec<u8, Msb0> = parser.unpack_as_with::<_, HmLabel>(n).context("label")?;
let m = n - prefix.len() as u32;
Ok(Hashmap {
prefix,
node: parser
.parse_as_with::<_, HashmapAugNode<AsT, AsE>>((m, node_args, extra_args))
.context("node")?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HashmapNode<T, E = ()> {
Leaf(T),
Fork([Box<Hashmap<T, E>>; 2]),
}
impl<T, E> HashmapNode<T, E> {
#[inline]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
match self {
Self::Leaf(_) => 1,
Self::Fork([l, r]) => l.len() + r.len(),
}
}
#[inline]
pub fn contains_key(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> bool {
let key = key.as_ref();
match self {
Self::Leaf(_) if key.is_empty() => true,
Self::Fork([left, right]) => {
let Some((is_right, key)) = key.split_first() else {
return false;
};
if *is_right { right } else { left }.contains_key(key)
}
_ => false,
}
}
#[inline]
pub fn get(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&T> {
let key = key.as_ref();
match self {
Self::Leaf(v) if key.is_empty() => Some(v),
Self::Fork([left, right]) => {
let (is_right, key) = key.split_first()?;
if *is_right { right } else { left }.get(key)
}
_ => None,
}
}
#[inline]
pub fn get_mut(&mut self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&mut T> {
let key = key.as_ref();
match self {
Self::Leaf(v) if key.is_empty() => Some(v),
Self::Fork([left, right]) => {
let (is_right, key) = key.split_first()?;
if *is_right { right } else { left }.get_mut(key)
}
_ => None,
}
}
}
impl<T, AsT, E, AsE> CellSerializeAsWithArgs<HashmapNode<T, E>> for HashmapNode<AsT, AsE>
where
AsT: CellSerializeAsWithArgs<T>,
AsT::Args: Clone,
AsE: CellSerializeAsWithArgs<E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
fn store_as_with(
source: &HashmapNode<T, E>,
builder: &mut CellBuilder,
(n, node_args, extra_args): Self::Args,
) -> Result<(), CellBuilderError> {
match source {
HashmapNode::Leaf(value) => {
if n != 0 {
return Err(CellBuilderError::custom(format!(
"key is too small, {n} more bits required"
)));
}
builder.store_as_with::<_, &AsT>(value, node_args)?
}
HashmapNode::Fork(fork) => {
if n == 0 {
return Err(CellBuilderError::custom("key is too long"));
}
builder.store_as_with::<_, &[Box<Ref<Hashmap<AsT, AsE>>>; 2]>(
fork,
(n - 1, node_args, extra_args),
)?
}
};
Ok(())
}
}
impl<'de, T, AsT, E, AsE> CellDeserializeAsWithArgs<'de, HashmapNode<T, E>>
for HashmapNode<AsT, AsE>
where
AsT: CellDeserializeAsWithArgs<'de, T>,
AsT::Args: Clone,
AsE: CellDeserializeAsWithArgs<'de, E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
#[inline]
fn parse_as_with(
parser: &mut CellParser<'de>,
(n, node_args, extra_args): Self::Args,
) -> Result<HashmapNode<T, E>, CellParserError<'de>> {
if n == 0 {
return parser
.parse_as_with::<_, AsT>(node_args)
.map(HashmapNode::Leaf);
}
Ok(HashmapNode::Fork(
parser
.parse_as_with::<_, [Box<Ref<ParseFully<Hashmap<AsT, AsE>>>>; 2]>((
n - 1,
node_args,
extra_args,
))?,
))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[autoimpl(Deref using self.node)]
#[autoimpl(DerefMut using self.node)]
pub struct HashmapAugNode<T, E = ()> {
pub node: HashmapNode<T, E>,
pub extra: E,
}
impl<T, E> HashmapAugNode<T, E> {
#[inline]
pub fn new(node: HashmapNode<T, E>, extra: E) -> Self {
Self { node, extra }
}
}
impl<T, AsT, E, AsE> CellSerializeAsWithArgs<HashmapAugNode<T, E>> for HashmapAugNode<AsT, AsE>
where
AsT: CellSerializeAsWithArgs<T>,
AsT::Args: Clone,
AsE: CellSerializeAsWithArgs<E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
fn store_as_with(
source: &HashmapAugNode<T, E>,
builder: &mut CellBuilder,
(n, node_args, extra_args): Self::Args,
) -> Result<(), CellBuilderError> {
builder
.store_as_with::<_, &AsE>(&source.extra, extra_args.clone())?
.store_as_with::<_, &HashmapNode<AsT, AsE>>(&source.node, (n, node_args, extra_args))?;
Ok(())
}
}
impl<'de, T, AsT, E, AsE> CellDeserializeAsWithArgs<'de, HashmapAugNode<T, E>>
for HashmapAugNode<AsT, AsE>
where
AsT: CellDeserializeAsWithArgs<'de, T>,
AsT::Args: Clone,
AsE: CellDeserializeAsWithArgs<'de, E>,
AsE::Args: Clone,
{
type Args = (u32, AsT::Args, AsE::Args);
fn parse_as_with(
parser: &mut CellParser<'de>,
(n, node_args, extra_args): Self::Args,
) -> Result<HashmapAugNode<T, E>, CellParserError<'de>> {
Ok(HashmapAugNode {
extra: parser.parse_as_with::<_, AsE>(extra_args.clone())?,
node: parser.parse_as_with::<_, HashmapNode<AsT, AsE>>((n, node_args, extra_args))?,
})
}
}
#[cfg(test)]
mod tests {
use tlb::{
bits::bitvec::{bits, order::Msb0, view::AsBits},
r#as::{Data, NoArgs},
ser::{r#as::CellSerializeWrapAsExt, CellSerializeExt},
Cell,
};
use super::*;
#[test]
fn parse() {
let cell = (
bits![u8, Msb0; 1].wrap_as::<Data>(),
(
bits![u8, Msb0; 0,0].wrap_as::<Data>(),
(
bits![u8, Msb0; 0,1,1,0,0,0].wrap_as::<Data>(),
bits![u8, Msb0; 1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1]
.wrap_as::<Ref<Data>>(),
bits![u8, Msb0; 1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1]
.wrap_as::<Ref<Data>>(),
)
.wrap_as::<Ref>(),
bits![u8, Msb0; 1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1].wrap_as::<Ref<Data>>(),
)
.wrap_as::<Ref>(),
)
.to_cell()
.unwrap();
let hm: HashmapE<u16> = cell
.parse_fully_as_with::<_, HashmapE<Data<NoArgs<_>>, NoArgs<_>>>((8, (), ()))
.unwrap();
assert_eq!(hm.len(), 3);
assert_eq!(hm.get(1u8.to_be_bytes().as_bits()), Some(&777));
assert_eq!(hm.get(17u8.to_be_bytes().as_bits()), Some(&111));
assert_eq!(hm.get(128u8.to_be_bytes().as_bits()), Some(&777));
let mut builder = Cell::builder();
builder
.store_as_with::<_, HashmapE<Data<NoArgs<_>>, NoArgs<_>>>(hm, (8, (), ()))
.unwrap();
let got = builder.into_cell();
assert_eq!(got, cell);
}
}