hexane 0.2.1

A columnar compression library used by automerge
Documentation
use super::boolean::BooleanCursorInternal;
use super::cursor::{ColumnCursor, Run};
use super::delta::DeltaCursorInternal;
use super::pack::Packable;
use super::raw::RawCursorInternal;
use super::rle::RleCursor;
use crate::ColumnData;
use std::borrow::Borrow;

pub(crate) trait TestDumpable<T: Packable + ?Sized> {
    fn test_dump(data: &[u8]) -> Vec<ColExport<T>>;
}

impl<const B: usize, P: Packable + ?Sized> TestDumpable<P> for RleCursor<B, P> {
    fn test_dump(data: &[u8]) -> Vec<ColExport<P>> {
        let mut cursor = Self::default();
        let mut current = None;
        let mut result = vec![];
        while let Some(run) = cursor.next(data) {
            match run {
                Run { count, value: None } => {
                    if let Some(run) = current.take() {
                        result.push(ColExport::litrun(run))
                    }
                    result.push(ColExport::Null(count))
                }
                Run {
                    count: 1,
                    value: Some(v),
                } => {
                    if cursor.num_left() == 0 {
                        let mut run = current.take().unwrap_or_default();
                        run.push(v);
                        result.push(ColExport::litrun(run))
                    } else if let Some(run) = &mut current {
                        run.push(v);
                    } else {
                        current = Some(vec![v]);
                    }
                }
                Run {
                    count,
                    value: Some(v),
                } => {
                    if let Some(run) = current.take() {
                        result.push(ColExport::litrun(run))
                    }
                    result.push(ColExport::run(count, v))
                }
            }
        }
        if let Some(run) = current.take() {
            result.push(ColExport::litrun(run))
        }
        result
    }
}

impl<const B: usize> TestDumpable<bool> for BooleanCursorInternal<B> {
    fn test_dump(data: &[u8]) -> Vec<ColExport<bool>> {
        let mut result = vec![];
        let mut cursor = Self::default();
        while let Ok(Some(Run { count, value })) = cursor.try_next(data) {
            if count > 0 {
                result.push(ColExport::Run(count, *value.unwrap()))
            }
        }
        result
    }
}
impl<const B: usize> TestDumpable<i64> for DeltaCursorInternal<B> {
    fn test_dump(data: &[u8]) -> Vec<ColExport<i64>> {
        super::delta::SubCursor::<B>::test_dump(data)
    }
}

impl<const B: usize> TestDumpable<[u8]> for RawCursorInternal<B> {
    fn test_dump(data: &[u8]) -> Vec<ColExport<[u8]>> {
        vec![ColExport::Raw(data.to_vec())]
    }
}

#[allow(private_bounds)]
impl<C: ColumnCursor + TestDumpable<<C as ColumnCursor>::Item>> ColumnData<C> {
    pub(crate) fn test_dump(&self) -> Vec<Vec<ColExport<C::Item>>> {
        self.slabs
            .iter()
            .map(|s| <C as TestDumpable<C::Item>>::test_dump(s.as_slice()))
            .collect()
    }
}

#[derive(Debug, Clone, PartialEq)]
pub(crate) enum ColExport<P: Packable + ?Sized> {
    LitRun(Vec<P::Owned>),
    Run(usize, P::Owned),
    Raw(Vec<u8>),
    Null(usize),
}

impl<P: Packable + ?Sized> ColExport<P> {
    pub(crate) fn litrun<X: Borrow<P>>(items: Vec<X>) -> Self {
        Self::LitRun(items.into_iter().map(|i| i.borrow().to_owned()).collect())
    }
    pub(crate) fn run<X: Borrow<P>>(count: usize, item: X) -> Self {
        Self::Run(count, item.borrow().to_owned())
    }
}