use std::hash::{Hash, Hasher};
use crate::{
subtree_path::SubtreePathInner,
util::{CompactBytes, CowLike},
SubtreePath, SubtreePathIter,
};
#[derive(Debug)]
pub struct SubtreePathBuilder<'b, B> {
pub(crate) base: SubtreePath<'b, B>,
pub(crate) relative: SubtreePathRelative<'b>,
}
impl<'b, B: AsRef<[u8]>> Hash for SubtreePathBuilder<'b, B> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.relative.hash(state);
self.base.hash(state);
}
}
impl<'bl, 'br, BL, BR> PartialEq<SubtreePathBuilder<'br, BR>> for SubtreePathBuilder<'bl, BL>
where
BL: AsRef<[u8]>,
BR: AsRef<[u8]>,
{
fn eq(&self, other: &SubtreePathBuilder<'br, BR>) -> bool {
self.reverse_iter().eq(other.reverse_iter())
}
}
impl<'bl, 'br, BL, BR> PartialEq<SubtreePathBuilder<'br, BR>> for SubtreePath<'bl, BL>
where
BL: AsRef<[u8]>,
BR: AsRef<[u8]>,
{
fn eq(&self, other: &SubtreePathBuilder<'br, BR>) -> bool {
self.clone().into_reverse_iter().eq(other.reverse_iter())
}
}
impl<'bl, 'br, BL, BR> PartialEq<SubtreePath<'br, BR>> for SubtreePathBuilder<'bl, BL>
where
BL: AsRef<[u8]>,
BR: AsRef<[u8]>,
{
fn eq(&self, other: &SubtreePath<'br, BR>) -> bool {
self.reverse_iter().eq(other.clone().into_reverse_iter())
}
}
impl<'b, B: AsRef<[u8]>> Eq for SubtreePathBuilder<'b, B> {}
impl<'s, 'b, B> From<&'s SubtreePath<'b, B>> for SubtreePathBuilder<'b, B> {
fn from(value: &'s SubtreePath<'b, B>) -> Self {
SubtreePathBuilder {
base: value.clone(),
relative: SubtreePathRelative::Empty,
}
}
}
#[derive(Debug)]
pub(crate) enum SubtreePathRelative<'r> {
Empty,
Single(CowLike<'r>),
Multi(CompactBytes),
}
impl SubtreePathRelative<'_> {
pub fn len(&self) -> usize {
match self {
SubtreePathRelative::Empty => 0,
SubtreePathRelative::Single(_) => 1,
SubtreePathRelative::Multi(cb) => cb.len(),
}
}
pub fn is_empty(&self) -> bool {
matches!(self, SubtreePathRelative::Empty)
}
}
impl Hash for SubtreePathRelative<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
SubtreePathRelative::Empty => {}
SubtreePathRelative::Single(segment) => segment.hash(state),
SubtreePathRelative::Multi(bytes) => {
bytes.reverse_iter().for_each(|segment| segment.hash(state))
}
}
}
}
impl SubtreePathBuilder<'static, [u8; 0]> {
pub fn new() -> Self {
SubtreePathBuilder {
base: [].as_ref().into(),
relative: SubtreePathRelative::Empty,
}
}
}
impl Default for SubtreePathBuilder<'static, [u8; 0]> {
fn default() -> Self {
Self::new()
}
}
impl<B> SubtreePathBuilder<'_, B> {
pub fn len(&self) -> usize {
self.base.len() + self.relative.len()
}
pub fn is_empty(&self) -> bool {
self.base.is_empty() && self.relative.is_empty()
}
}
impl<'b, B: AsRef<[u8]>> SubtreePathBuilder<'b, B> {
pub fn derive_owned(&'b self) -> SubtreePathBuilder<'b, B> {
match self.relative {
SubtreePathRelative::Empty => self.base.derive_owned(),
_ => SubtreePathBuilder {
base: SubtreePathInner::SubtreePath(self).into(),
relative: SubtreePathRelative::Empty,
},
}
}
pub fn derive_parent(&self) -> Option<(SubtreePath<B>, &[u8])> {
match &self.relative {
SubtreePathRelative::Empty => self.base.derive_parent(),
SubtreePathRelative::Single(relative) => Some((self.base.clone(), relative.as_ref())),
SubtreePathRelative::Multi(_) => {
let mut iter = self.reverse_iter();
iter.next()
.map(|segment| (SubtreePathInner::SubtreePathIter(iter).into(), segment))
}
}
}
pub fn derive_owned_with_child<'s, S>(&'b self, segment: S) -> SubtreePathBuilder<'b, B>
where
S: Into<CowLike<'s>>,
's: 'b,
{
SubtreePathBuilder {
base: SubtreePathInner::SubtreePath(self).into(),
relative: SubtreePathRelative::Single(segment.into()),
}
}
pub fn push_segment(&mut self, segment: &[u8]) {
match &mut self.relative {
SubtreePathRelative::Empty => {
let mut bytes = CompactBytes::new();
bytes.add_segment(segment);
self.relative = SubtreePathRelative::Multi(bytes);
}
SubtreePathRelative::Single(old_segment) => {
let mut bytes = CompactBytes::new();
bytes.add_segment(old_segment);
bytes.add_segment(segment);
self.relative = SubtreePathRelative::Multi(bytes);
}
SubtreePathRelative::Multi(bytes) => bytes.add_segment(segment),
}
}
pub fn reverse_iter(&'b self) -> SubtreePathIter<'b, B> {
match &self.relative {
SubtreePathRelative::Empty => self.base.clone().into_reverse_iter(),
SubtreePathRelative::Single(item) => {
SubtreePathIter::new_with_next(item.as_ref(), &self.base)
}
SubtreePathRelative::Multi(bytes) => {
SubtreePathIter::new_with_next(bytes.reverse_iter(), &self.base)
}
}
}
pub fn to_vec(&self) -> Vec<Vec<u8>> {
let mut result = Vec::new();
match &self.relative {
SubtreePathRelative::Empty => {}
SubtreePathRelative::Single(s) => result.push(s.to_vec()),
SubtreePathRelative::Multi(bytes) => {
bytes.reverse_iter().for_each(|s| result.push(s.to_vec()))
}
}
match &self.base.ref_variant {
SubtreePathInner::Slice(slice) => slice
.iter()
.rev()
.for_each(|x| result.push(x.as_ref().to_vec())),
SubtreePathInner::SubtreePath(path) => {
path.reverse_iter().for_each(|x| result.push(x.to_vec()))
}
SubtreePathInner::SubtreePathIter(iter) => {
iter.clone().for_each(|x| result.push(x.as_ref().to_vec()))
}
};
result.reverse();
result
}
pub fn is_root(&self) -> bool {
match self {
Self {
base,
relative: SubtreePathRelative::Empty,
} => base.is_root(),
_ => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_vec() {
let base: SubtreePath<_> = (&[b"one" as &[u8], b"two", b"three"]).into();
let mut builder = base.derive_owned_with_child(b"four");
builder.push_segment(b"five");
builder.push_segment(b"six");
builder.push_segment(b"seven");
let as_vec = builder.to_vec();
let reference_vec = vec![
b"one".to_vec(),
b"two".to_vec(),
b"three".to_vec(),
b"four".to_vec(),
b"five".to_vec(),
b"six".to_vec(),
b"seven".to_vec(),
];
assert_eq!(as_vec, reference_vec);
assert_eq!(builder.len(), reference_vec.len());
}
}