use crate::{Arc, UpdateMap};
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
use std::collections::BTreeMap;
use tree_hash::{Hash256, TreeHash, TreeHashType};
#[derive(Debug)]
pub enum MaybeArced<T> {
Arced(Arc<T>),
Unarced(T),
}
impl<T> MaybeArced<T> {
pub fn arced(self) -> Arc<T> {
match self {
Self::Arced(arc) => arc,
Self::Unarced(value) => Arc::new(value),
}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct Length(pub usize);
impl Length {
#[allow(clippy::should_implement_trait)]
pub fn as_mut(&mut self) -> &mut usize {
&mut self.0
}
#[inline(always)]
pub fn as_usize(&self) -> usize {
self.0
}
}
pub fn int_log(n: usize) -> usize {
match n.checked_next_power_of_two() {
Some(x) => x.trailing_zeros() as usize,
None => 8 * std::mem::size_of::<usize>(),
}
}
pub fn compute_level(index: usize, depth: usize, packing_depth: usize) -> usize {
let raw_level = if index == 0 {
depth + packing_depth
} else {
index.trailing_zeros() as usize
};
if raw_level < packing_depth {
0
} else {
raw_level
}
}
pub fn opt_packing_factor<T: TreeHash>() -> Option<usize> {
match T::tree_hash_type() {
TreeHashType::Basic => Some(T::tree_hash_packing_factor()),
TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => None,
}
}
pub fn opt_packing_depth<T: TreeHash>() -> Option<usize> {
let packing_factor = opt_packing_factor::<T>()?;
Some(int_log(packing_factor))
}
pub fn max_btree_index<T>(map: &BTreeMap<usize, T>) -> Option<usize> {
map.keys().next_back().copied()
}
pub fn updated_length<U: UpdateMap<T>, T>(prev_len: Length, updates: &U) -> Length {
updates.max_index().map_or(prev_len, |max_idx| {
Length(std::cmp::max(max_idx + 1, prev_len.as_usize()))
})
}
pub fn opt_hash(
hashes: Option<&BTreeMap<(usize, usize), Hash256>>,
depth: usize,
prefix: usize,
) -> Option<Hash256> {
hashes?.get(&(depth, prefix)).copied()
}
#[cfg(feature = "arbitrary")]
pub fn arb_arc<'a, T: Arbitrary<'a>>(
u: &mut arbitrary::Unstructured<'a>,
) -> arbitrary::Result<Arc<T>> {
T::arbitrary(u).map(Arc::new)
}
#[cfg(feature = "arbitrary")]
pub fn arb_rwlock<'a, T: Arbitrary<'a>>(
u: &mut arbitrary::Unstructured<'a>,
) -> arbitrary::Result<parking_lot::RwLock<T>> {
T::arbitrary(u).map(parking_lot::RwLock::new)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn odd_index_level() {
let depth = 5;
let packing_depth = 0;
for i in (0..2usize.pow(depth as u32)).filter(|i| i % 2 == 1) {
assert_eq!(compute_level(i, depth, packing_depth), 0);
}
}
#[test]
fn packing_depth_level() {
let depth = 10;
let packing_depth = 3;
assert_eq!(
compute_level(0, depth, packing_depth),
depth + packing_depth
);
assert_eq!(compute_level(1, depth, packing_depth), 0);
assert_eq!(compute_level(2, depth, packing_depth), 0);
assert_eq!(compute_level(4, depth, packing_depth), 0);
assert_eq!(compute_level(8, depth, packing_depth), 3);
}
}