use std::borrow::Cow;
use std::ops::Deref;
#[cfg(feature = "unstable-v2")]
use std::rc::Rc;
#[cfg(feature = "unstable-v2")]
use bitvec::order::Lsb0;
#[cfg(feature = "unstable-v2")]
use bitvec::slice::BitSlice;
#[cfg(feature = "unstable-v2")]
use bitvec::vec::BitVec;
use enum_dispatch::enum_dispatch;
#[cfg(feature = "unstable-v2")]
use crate::decoder::Alp;
use crate::decoder::RawStream;
use crate::utils::Presence;
use crate::{DecodeState, Lazy, PropKind};
pub type Property<'a, S = Lazy> =
<S as DecodeState>::LazyOrParsed<RawProperty<'a>, ParsedProperty<'a>>;
#[derive(Debug, Clone, PartialEq)]
pub struct RawScalar<'a> {
pub(crate) name: &'a str,
pub(crate) presence: RawPresence<'a>,
pub(crate) data: RawStream<'a>,
}
impl<'a> RawScalar<'a> {
pub(crate) fn new(name: &'a str, presence: RawPresence<'a>, data: RawStream<'a>) -> Self {
Self {
name,
presence,
data,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawFloats<'a> {
pub name: &'a str,
pub presence: RawPresence<'a>,
pub encoding: RawFloatsEncoding<'a>,
}
impl<'a> RawFloats<'a> {
pub(crate) fn single(name: &'a str, presence: RawPresence<'a>, data: RawStream<'a>) -> Self {
Self {
name,
presence,
encoding: RawFloatsEncoding::Single(data),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum RawFloatsEncoding<'a> {
Single(RawStream<'a>),
#[cfg(feature = "unstable-v2")]
Dictionary {
codes: RawStream<'a>,
dictionary: RawStream<'a>,
},
#[cfg(feature = "unstable-v2")]
Alp { params: Alp, data: RawStream<'a> },
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawStrings<'a> {
pub name: &'a str,
pub presence: RawPresence<'a>,
pub encoding: RawStringsEncoding<'a>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum RawStringsEncoding<'a> {
Plain(RawPlainData<'a>),
Dictionary {
plain_data: RawPlainData<'a>,
offsets: RawStream<'a>,
dict: DictLayout,
},
FsstPlain(RawFsstData<'a>),
FsstDictionary {
fsst_data: RawFsstData<'a>,
offsets: RawStream<'a>,
dict: DictLayout,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, strum::EnumIter)]
pub enum DictLayout {
Plain,
#[cfg(feature = "unstable-v2")]
FrontCoded,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum StringLayout {
Plain,
Dict,
Fsst,
FsstDict,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ColumnDecl {
Id { wide: bool, optional: bool },
Value { kind: PropKind, optional: bool },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ColumnStorage {
pub string: Option<StringLayout>,
pub dictionary: Option<DictLayout>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum RawSharedDictEncoding<'a> {
Plain(RawPlainData<'a>),
FsstPlain(RawFsstData<'a>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawSharedDict<'a> {
pub name: &'a str,
pub encoding: RawSharedDictEncoding<'a>,
pub dict: DictLayout,
pub children: Vec<RawSharedDictItem<'a>>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum RawProperty<'a> {
Bool(RawScalar<'a>),
I8(RawScalar<'a>),
U8(RawScalar<'a>),
I32(RawScalar<'a>),
U32(RawScalar<'a>),
I64(RawScalar<'a>),
U64(RawScalar<'a>),
F32(RawFloats<'a>),
F64(RawFloats<'a>),
Str(RawStrings<'a>),
SharedDict(RawSharedDict<'a>),
}
#[derive(Clone, Debug, PartialEq, strum::IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
#[enum_dispatch(Analyze)]
pub enum ParsedProperty<'a> {
Bool(ParsedScalar<'a, bool>),
I8(ParsedScalar<'a, i8>),
U8(ParsedScalar<'a, u8>),
I32(ParsedScalar<'a, i32>),
U32(ParsedScalar<'a, u32>),
I64(ParsedScalar<'a, i64>),
U64(ParsedScalar<'a, u64>),
F32(ParsedScalar<'a, f32>),
F64(ParsedScalar<'a, f64>),
Str(ParsedStrings<'a>),
SharedDict(ParsedSharedDict<'a>),
}
macro_rules! impl_parsed_property_kind {
(
scalar { $($sv:ident),* $(,)? }
string { $($gv:ident),* $(,)? }
) => {
impl ParsedProperty<'_> {
#[must_use]
pub fn kind(&self) -> PropKind {
match self {
$(Self::$sv(_) => PropKind::$sv,)*
$(Self::$gv(_) => PropKind::$gv,)*
Self::SharedDict(_) => PropKind::Str,
}
}
}
};
}
with_kinds!(impl_parsed_property_kind);
#[derive(Clone, Debug, PartialEq)]
pub struct ParsedScalar<'a, T: Copy + PartialEq> {
pub(crate) name: &'a str,
pub(crate) presence: Presence<'a, T>,
}
impl<'a, T: Copy + PartialEq> Deref for ParsedScalar<'a, T> {
type Target = Presence<'a, T>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.presence
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct DictRange {
pub start: i32,
pub end: i32,
}
impl DictRange {
pub const NULL: Self = Self { start: -1, end: -1 };
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(all(not(test), feature = "arbitrary"), derive(arbitrary::Arbitrary))]
pub struct ParsedSharedDictItem<'a> {
pub(crate) suffix: &'a str,
pub(crate) ranges: Vec<DictRange>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParsedStrings<'a> {
pub(crate) name: &'a str,
pub(crate) lengths: Vec<i32>,
pub(crate) data: Cow<'a, str>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParsedSharedDict<'a> {
pub(crate) prefix: &'a str,
pub(crate) data: Cow<'a, str>,
pub(crate) items: Vec<ParsedSharedDictItem<'a>>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct RawSharedDictItem<'a> {
pub name: &'a str,
pub presence: RawPresence<'a>,
pub data: RawStream<'a>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawPlainData<'a> {
pub lengths: RawStream<'a>,
pub data: RawStream<'a>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawFsstData<'a> {
pub symbol_lengths: RawStream<'a>,
pub symbol_table: RawStream<'a>,
pub lengths: RawStream<'a>,
pub corpus: RawStream<'a>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub enum RawPresence<'a> {
#[default]
AllPresent,
Stream(RawStream<'a>),
#[cfg(feature = "unstable-v2")]
Bitfield(&'a BitSlice<u8, Lsb0>),
#[cfg(feature = "unstable-v2")]
Decoded(Rc<BitVec<u8, Lsb0>>),
}
#[cfg(feature = "unstable-v2")]
impl<'a> RawPresence<'a> {
pub(crate) fn from_bits(bits: Cow<'a, BitSlice<u8, Lsb0>>) -> Self {
match bits {
Cow::Borrowed(bits) => Self::Bitfield(bits),
Cow::Owned(bits) => Self::Decoded(Rc::new(bits)),
}
}
}
impl RawPresence<'_> {
#[must_use]
pub(crate) fn is_optional(&self) -> bool {
!matches!(self, Self::AllPresent)
}
}
impl RawProperty<'_> {
#[must_use]
pub(crate) fn storage(&self) -> Option<ColumnStorage> {
let (string, dictionary) = match self {
Self::Str(column) => match &column.encoding {
RawStringsEncoding::Plain(_) => (StringLayout::Plain, None),
RawStringsEncoding::Dictionary { dict, .. } => (StringLayout::Dict, Some(*dict)),
RawStringsEncoding::FsstPlain(_) => (StringLayout::Fsst, None),
RawStringsEncoding::FsstDictionary { dict, .. } => {
(StringLayout::FsstDict, Some(*dict))
}
},
Self::SharedDict(column) => match &column.encoding {
RawSharedDictEncoding::Plain(_) => (StringLayout::Dict, Some(column.dict)),
RawSharedDictEncoding::FsstPlain(_) => (StringLayout::FsstDict, Some(column.dict)),
},
Self::Bool(_)
| Self::I8(_)
| Self::U8(_)
| Self::I32(_)
| Self::U32(_)
| Self::I64(_)
| Self::U64(_)
| Self::F32(_)
| Self::F64(_) => return None,
};
Some(ColumnStorage {
string: Some(string),
dictionary,
})
}
}
impl RawProperty<'_> {
pub(crate) fn for_each_decl(&self, cb: &mut dyn FnMut(ColumnDecl)) {
let (kind, optional) = match self {
Self::Bool(c) => (PropKind::Bool, c.presence.is_optional()),
Self::I8(c) => (PropKind::I8, c.presence.is_optional()),
Self::U8(c) => (PropKind::U8, c.presence.is_optional()),
Self::I32(c) => (PropKind::I32, c.presence.is_optional()),
Self::U32(c) => (PropKind::U32, c.presence.is_optional()),
Self::I64(c) => (PropKind::I64, c.presence.is_optional()),
Self::U64(c) => (PropKind::U64, c.presence.is_optional()),
Self::F32(c) => (PropKind::F32, c.presence.is_optional()),
Self::F64(c) => (PropKind::F64, c.presence.is_optional()),
Self::Str(c) => (PropKind::Str, c.presence.is_optional()),
Self::SharedDict(c) => {
for child in &c.children {
cb(ColumnDecl::Value {
kind: PropKind::Str,
optional: child.presence.is_optional(),
});
}
return;
}
};
cb(ColumnDecl::Value { kind, optional });
}
}