use crate::{
forest::TreeTypes,
store::{ReadOnlyStore, ZstdDagCborSeq},
CipherOffset, Forest, Secrets,
};
use anyhow::{anyhow, Result};
use libipld::{
cbor::{DagCbor, DagCborCodec},
codec::{Decode, Encode},
DagCbor,
};
use std::{
convert::TryFrom,
fmt::{self, Debug, Display},
io,
iter::FromIterator,
ops::Range,
sync::Arc,
};
pub trait Summarizable<T> {
fn summarize(&self) -> T;
}
pub trait CompactSeq: DagCbor {
type Item;
fn len(&self) -> usize;
fn get(&self, index: usize) -> Option<Self::Item>;
fn first(&self) -> Self::Item {
self.get(0).unwrap()
}
fn last(&self) -> Self::Item {
self.get(self.len() - 1).unwrap()
}
fn to_vec(&self) -> Vec<Self::Item> {
(0..self.len()).map(move |i| self.get(i).unwrap()).collect()
}
fn select(&self, bits: &[bool]) -> Vec<Self::Item> {
(0..self.len())
.filter_map(move |i| if bits[i] { self.get(i) } else { None })
.collect()
}
fn count(&self) -> u64 {
self.len() as u64
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn estimated_size(&self) -> usize {
self.len() * std::mem::size_of::<Self::Item>()
}
}
#[derive(Debug, DagCbor)]
pub struct LeafIndex<T: TreeTypes> {
pub sealed: bool,
pub link: Option<T::Link>,
pub keys: T::KeySeq,
pub value_bytes: u64,
}
impl<T: TreeTypes> Clone for LeafIndex<T> {
fn clone(&self) -> Self {
Self {
sealed: self.sealed,
value_bytes: self.value_bytes,
link: self.link,
keys: self.keys.clone(),
}
}
}
impl<T: TreeTypes> LeafIndex<T> {
pub fn keys(&self) -> impl Iterator<Item = T::Key> {
self.keys.to_vec().into_iter()
}
pub fn select_keys(&self, bits: &[bool]) -> impl Iterator<Item = T::Key> {
self.keys.select(bits).into_iter()
}
}
#[derive(Debug, DagCbor)]
pub struct BranchIndex<T: TreeTypes> {
pub count: u64,
pub level: u32,
pub sealed: bool,
pub link: Option<T::Link>,
pub summaries: T::SummarySeq,
pub value_bytes: u64,
pub key_bytes: u64,
}
impl<T: TreeTypes> Clone for BranchIndex<T> {
fn clone(&self) -> Self {
Self {
count: self.count,
level: self.level,
sealed: self.sealed,
value_bytes: self.value_bytes,
key_bytes: self.key_bytes,
link: self.link,
summaries: self.summaries.clone(),
}
}
}
impl<T: TreeTypes> BranchIndex<T> {
pub fn summaries(&self) -> impl Iterator<Item = T::Summary> + '_ {
self.summaries.to_vec().into_iter()
}
}
#[derive(Debug, DagCbor)]
#[ipld(repr = "kinded")]
pub enum Index<T: TreeTypes> {
#[ipld(repr = "value")]
Leaf(Arc<LeafIndex<T>>),
#[ipld(repr = "value")]
Branch(Arc<BranchIndex<T>>),
}
impl<T: TreeTypes> From<LeafIndex<T>> for Index<T> {
fn from(value: LeafIndex<T>) -> Self {
Index::Leaf(Arc::new(value))
}
}
impl<T: TreeTypes> From<BranchIndex<T>> for Index<T> {
fn from(value: BranchIndex<T>) -> Self {
Index::Branch(Arc::new(value))
}
}
impl<T: TreeTypes> Clone for Index<T> {
fn clone(&self) -> Self {
match self {
Index::Leaf(x) => Index::Leaf(x.clone()),
Index::Branch(x) => Index::Branch(x.clone()),
}
}
}
impl<T: TreeTypes> Index<T> {
pub fn summarize(&self) -> T::Summary {
match self {
Index::Leaf(x) => x.keys.summarize(),
Index::Branch(x) => x.summaries.summarize(),
}
}
pub fn link(&self) -> &Option<T::Link> {
match self {
Index::Leaf(x) => &x.link,
Index::Branch(x) => &x.link,
}
}
pub fn count(&self) -> u64 {
match self {
Index::Leaf(x) => x.keys.count(),
Index::Branch(x) => x.count,
}
}
pub fn sealed(&self) -> bool {
match self {
Index::Leaf(x) => x.sealed,
Index::Branch(x) => x.sealed,
}
}
pub fn level(&self) -> u32 {
match self {
Index::Leaf(_) => 0,
Index::Branch(x) => x.level,
}
}
pub fn value_bytes(&self) -> u64 {
match self {
Index::Leaf(x) => x.value_bytes,
Index::Branch(x) => x.value_bytes,
}
}
pub fn key_bytes(&self) -> u64 {
match self {
Index::Leaf(_) => 0,
Index::Branch(x) => x.key_bytes,
}
}
}
#[derive(Debug, Clone)]
pub struct Branch<T: TreeTypes> {
pub children: Arc<[Index<T>]>,
pub byte_range: Range<u64>,
}
impl<T: TreeTypes> Branch<T> {
pub fn new(children: Vec<Index<T>>, byte_range: Range<u64>) -> Self {
assert!(!children.is_empty());
Self {
children: children.into(),
byte_range,
}
}
pub fn last_child(&self) -> &Index<T> {
self.children
.last()
.expect("branch can never have 0 children")
}
pub fn first_child(&self) -> &Index<T> {
self.children
.first()
.expect("branch can never have 0 children")
}
pub fn count(&self) -> u64 {
self.children.len() as u64
}
}
#[derive(Debug)]
pub struct Leaf {
pub items: ZstdDagCborSeq,
pub byte_range: Range<u64>,
}
impl Leaf {
pub fn new(items: ZstdDagCborSeq, byte_range: Range<u64>) -> Self {
Self { items, byte_range }
}
pub fn child_at<T: DagCbor>(&self, offset: u64) -> Result<T> {
self.as_ref()
.get(offset)?
.ok_or_else(|| anyhow!("index out of bounds {}", offset))
}
}
impl AsRef<ZstdDagCborSeq> for Leaf {
fn as_ref(&self) -> &ZstdDagCborSeq {
&self.items
}
}
#[derive(Debug)]
pub struct BranchLoader<T: TreeTypes, R> {
forest: Forest<T, R>,
secrets: Secrets,
link: T::Link,
}
impl<T: TreeTypes, R: ReadOnlyStore<T::Link>> BranchLoader<T, R> {
pub fn new(forest: &Forest<T, R>, secrets: &Secrets, link: T::Link) -> Self {
Self {
forest: forest.clone(),
secrets: secrets.clone(),
link,
}
}
pub fn load_cached(&self) -> anyhow::Result<Branch<T>> {
self.forest
.load_branch_cached_from_link(&self.secrets, &self.link)
}
pub fn load(&self) -> anyhow::Result<Branch<T>> {
self.forest.load_branch_from_link(&self.secrets, &self.link)
}
}
#[derive(Debug)]
pub struct LeafLoader<T: TreeTypes, R> {
forest: Forest<T, R>,
secrets: Secrets,
link: T::Link,
}
impl<T: TreeTypes, R: ReadOnlyStore<T::Link>> LeafLoader<T, R> {
pub fn new(forest: &Forest<T, R>, secrets: &Secrets, link: T::Link) -> Self {
Self {
forest: forest.clone(),
secrets: secrets.clone(),
link,
}
}
pub fn load(&self) -> anyhow::Result<Leaf> {
self.forest.load_leaf_from_link(&self.secrets, &self.link)
}
}
#[derive(Debug)]
pub enum NodeInfo<T: TreeTypes, R> {
Branch(Arc<BranchIndex<T>>, BranchLoader<T, R>),
Leaf(Arc<LeafIndex<T>>, LeafLoader<T, R>),
PurgedBranch(Arc<BranchIndex<T>>),
PurgedLeaf(Arc<LeafIndex<T>>),
}
impl<T: TreeTypes, R> Display for NodeInfo<T, R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Leaf(index, _) => {
write!(
f,
"Leaf(count={}, value_bytes={}, sealed={}, link={})",
index.keys.count(),
index.value_bytes,
index.sealed,
index
.link
.map(|x| format!("{}", x))
.unwrap_or_else(|| "".to_string())
)
}
Self::Branch(index, _) => {
write!(
f,
"Branch(count={}, key_bytes={}, value_bytes={}, sealed={}, link={}, children={})",
index.count,
index.key_bytes,
index.value_bytes,
index.sealed,
index
.link
.map(|x| format!("{}", x))
.unwrap_or_else(|| "".to_string()),
index.summaries.len()
)
}
Self::PurgedBranch(index) => {
write!(
f,
"PurgedBranch(count={}, key_bytes={}, value_bytes={}, sealed={})",
index.count, index.key_bytes, index.value_bytes, index.sealed,
)
}
Self::PurgedLeaf(index) => {
write!(
f,
"PurgedLeaf(count={}, key_bytes={}, sealed={})",
index.keys.count(),
index.value_bytes,
index.sealed,
)
}
}
}
}
pub(crate) fn serialize_compressed<T: TreeTypes>(
key: &chacha20::Key,
nonce: &chacha20::XNonce,
state: &mut CipherOffset,
items: &[Index<T>],
level: i32,
) -> Result<Vec<u8>> {
let zs = ZstdDagCborSeq::from_iter(items, level)?;
zs.into_encrypted(key, nonce, state)
}
pub(crate) fn deserialize_compressed<T: TreeTypes>(
key: &chacha20::Key,
nonce: &chacha20::XNonce,
ipld: &[u8],
) -> Result<(Vec<Index<T>>, Range<u64>)> {
let (seq, byte_range) = ZstdDagCborSeq::decrypt(ipld, key, nonce)?;
let seq = seq.items::<Index<T>>()?;
Ok((seq, byte_range))
}
pub(crate) fn zip_with_offset_ref<
'a,
I: IntoIterator<Item = &'a Index<T>> + 'a,
T: TreeTypes + 'a,
>(
value: I,
offset: u64,
) -> impl Iterator<Item = (&'a Index<T>, u64)> + 'a {
value.into_iter().scan(offset, |offset, x| {
let o0 = *offset;
*offset += x.count();
Some((x, o0))
})
}
impl<T: CompactSeq> Summarizable<()> for T {
fn summarize(&self) {}
}
#[derive(Debug, Clone)]
pub struct UnitSeq(usize);
impl Encode<DagCborCodec> for UnitSeq {
fn encode<W: io::Write>(&self, c: DagCborCodec, w: &mut W) -> anyhow::Result<()> {
(self.0 as u64).encode(c, w)
}
}
impl Decode<DagCborCodec> for UnitSeq {
fn decode<R: io::Read + io::Seek>(c: DagCborCodec, r: &mut R) -> anyhow::Result<Self> {
let t = u64::decode(c, r)?;
Ok(Self(usize::try_from(t)?))
}
}
impl CompactSeq for UnitSeq {
type Item = ();
fn get(&self, index: usize) -> Option<()> {
if index < self.0 {
Some(())
} else {
None
}
}
fn len(&self) -> usize {
self.0 as usize
}
}
impl FromIterator<()> for UnitSeq {
fn from_iter<T: IntoIterator<Item = ()>>(iter: T) -> Self {
Self(iter.into_iter().count())
}
}
#[derive(Debug, Clone, DagCbor)]
pub struct VecSeq<T: DagCbor>(Vec<T>);
impl<T: DagCbor> AsRef<[T]> for VecSeq<T> {
fn as_ref(&self) -> &[T] {
&self.0
}
}
impl<T: DagCbor + Clone> CompactSeq for VecSeq<T> {
type Item = T;
fn get(&self, index: usize) -> Option<T> {
self.0.get(index).cloned()
}
fn len(&self) -> usize {
self.0.len()
}
fn estimated_size(&self) -> usize {
std::mem::size_of::<Self>() + self.0.capacity() * std::mem::size_of::<T>()
}
}
impl<T: DagCbor> FromIterator<T> for VecSeq<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}