use super::label_type::DictLabelType;
use super::leading_bit_utils::{add_leading_bit, all_bits_same, common_prefix_len, remove_leading_bit};
use crate::tlb_adapters::DictValAdapter;
use num_bigint::BigUint;
use num_traits::{One, Zero};
use std::marker::PhantomData;
use std::mem::swap;
use ton_lib_core::cell::CellBuilder;
use ton_lib_core::cell::TonCell;
use ton_lib_core::error::TLCoreError;
use ton_lib_core::traits::tlb::TLB;
use ton_lib_core::types::tlb_core::UnaryLen;
pub struct DictDataBuilder<'a, T, VA: DictValAdapter<T>> {
keys_sorted: Vec<BigUint>, values_sorted: &'a [&'a T],
key_bits_len_left: usize,
_phantom: PhantomData<VA>,
}
impl<'a, T, VA: DictValAdapter<T>> DictDataBuilder<'a, T, VA> {
pub fn new(
key_bits_len: usize,
mut keys_sorted: Vec<BigUint>,
values_sorted: &'a [&'a T],
) -> Result<Self, TLCoreError> {
prepare_keys(&mut keys_sorted, key_bits_len)?;
let builder = DictDataBuilder {
keys_sorted,
values_sorted,
key_bits_len_left: key_bits_len,
_phantom: PhantomData,
};
Ok(builder)
}
pub fn build(mut self) -> Result<TonCell, TLCoreError> {
let mut builder = TonCell::builder();
if self.keys_sorted.is_empty() {
return builder.build();
}
let mut keys = vec![];
swap(&mut self.keys_sorted, &mut keys);
let keys = keys.into_iter().enumerate().collect();
self.fill_cell(&mut builder, keys)?;
builder.build()
}
fn fill_cell(&mut self, builder: &mut CellBuilder, keys: Vec<(usize, BigUint)>) -> Result<(), TLCoreError> {
if keys.len() == 1 {
let (orig_key_pos, remaining_key) = &keys[0];
return self.store_leaf(builder, *orig_key_pos, remaining_key);
}
let key_len_bits_left_original = self.key_bits_len_left;
let key = &keys[0].1;
let key_len = key.bits() as usize;
let common_prefix_len = common_prefix_len(key, &keys.last().unwrap().1);
let label = {
let ignored_suffix_len = key_len - common_prefix_len - 1;
key >> ignored_suffix_len
};
self.store_label(builder, &label)?;
let mut left_keys = Vec::with_capacity(keys.len() / 2);
let mut right_keys = Vec::with_capacity(keys.len() / 2);
let new_key_len = key_len - common_prefix_len - 1;
let new_key_mask = (BigUint::one() << new_key_len) - 1u32;
for (pos, key) in keys {
let new_key = key & new_key_mask.clone();
let is_right = new_key.bits() as usize == new_key_len;
let new_key_internal = add_leading_bit(&new_key, new_key_len - 1);
if is_right {
right_keys.push((pos, new_key_internal));
} else {
left_keys.push((pos, new_key_internal));
}
}
self.key_bits_len_left -= common_prefix_len + 1; let mut left_builder = TonCell::builder();
self.fill_cell(&mut left_builder, left_keys)?;
builder.write_ref(left_builder.build()?.into_ref())?;
let mut right_builder = TonCell::builder();
self.fill_cell(&mut right_builder, right_keys)?;
builder.write_ref(right_builder.build()?.into_ref())?;
self.key_bits_len_left = key_len_bits_left_original;
Ok(())
}
fn store_leaf(
&mut self,
builder: &mut CellBuilder,
orig_key_pos: usize,
label: &BigUint,
) -> Result<(), TLCoreError> {
self.store_label(builder, label)?;
VA::write(builder, self.values_sorted[orig_key_pos])?;
Ok(())
}
fn store_label(&self, builder: &mut CellBuilder, label: &BigUint) -> Result<(), TLCoreError> {
assert!(label.bits() > 0);
if label.is_one() {
builder.write_num(&0, 2)?;
return Ok(());
}
let all_bits_same = all_bits_same(label);
let label_len = label.bits() as usize - 1;
let label_len_len = (self.key_bits_len_left as f32 + 1.0).log2().ceil() as usize;
let fair_label = remove_leading_bit(label);
let same_label_len = if all_bits_same { 3 + label_len_len } else { usize::MAX };
let short_label_len = 2 + label_len * 2;
let long_label_len = 2 + label_len_len + label_len;
let mut label_type = DictLabelType::Short;
if long_label_len < short_label_len {
label_type = DictLabelType::Long;
}
if same_label_len < short_label_len {
label_type = DictLabelType::Same;
}
match label_type {
DictLabelType::Same => {
builder.write_bit(true)?;
builder.write_bit(true)?;
builder.write_bit(!fair_label.is_zero())?;
builder.write_num(&label_len, label_len_len)?;
}
DictLabelType::Short => {
builder.write_bit(false)?;
let unary_len = UnaryLen(label_len);
unary_len.write(builder)?;
builder.write_num(&fair_label, label_len)?;
}
DictLabelType::Long => {
builder.write_bit(true)?;
builder.write_bit(false)?;
builder.write_num(&label_len, label_len_len)?;
builder.write_num(&fair_label, label_len)?;
}
}
Ok(())
}
}
fn prepare_keys(keys: &mut [BigUint], key_bits_len: usize) -> Result<(), TLCoreError> {
for key in keys {
let received_len_bits = key.bits() as usize;
if received_len_bits > key_bits_len {
let err_str =
format!("dict key too long: expected max {key_bits_len} bits, got {received_len_bits} bits, key={key}");
return Err(TLCoreError::TLBWrongData(err_str));
}
*key = add_leading_bit(key, key_bits_len);
}
Ok(())
}