use std::{collections::BTreeMap, fmt::Display}; pub use brk_types::{Index, SeriesLeaf, SeriesLeafWithSchema, TreeNode}; pub use indexmap::IndexMap; #[cfg(feature = "derive")] pub use brk_traversable_derive::Traversable; use schemars::JsonSchema; use serde::Serialize; use vecdb::{ AggFold, AnyExportableVec, AnyVec, BytesVec, BytesVecValue, CachedVec, CompressionStrategy, DeltaOp, EagerVec, Formattable, LazyAggVec, LazyDeltaVec, LazyVecFrom1, LazyVecFrom2, LazyVecFrom3, RawStrategy, ReadOnlyCompressedVec, ReadOnlyRawVec, StoredVec, TypedVec, VecIndex, VecValue, }; pub trait Traversable { fn to_tree_node(&self) -> TreeNode; /// All vecs including hidden — used for disk writes, flushes, exports. fn iter_any_exportable(&self) -> impl Iterator; /// Only non-hidden vecs — used for building the public series list. fn iter_any_visible(&self) -> impl Iterator { self.iter_any_exportable() } } /// Helper to create a SeriesLeafWithSchema from a vec fn make_leaf(vec: &V) -> TreeNode { let index_str = I::to_string(); let index = Index::try_from(index_str).ok(); let indexes = index.into_iter().collect(); let leaf = SeriesLeaf::new( vec.name().to_string(), vec.value_type_to_string().to_string(), indexes, ); let schema = schemars::SchemaGenerator::default().into_root_schema_for::(); let schema_json = serde_json::to_value(schema).unwrap_or_default(); TreeNode::Leaf(SeriesLeafWithSchema::new(leaf, schema_json)) } // BytesVec implementation impl Traversable for BytesVec where I: VecIndex, T: BytesVecValue + Formattable + Serialize + JsonSchema, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } // ZeroCopyVec implementation (only if zerocopy feature enabled) #[cfg(feature = "zerocopy")] impl Traversable for vecdb::ZeroCopyVec where I: VecIndex, T: vecdb::ZeroCopyVecValue + Formattable + Serialize + JsonSchema, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } // PcoVec implementation (only if pco feature enabled) #[cfg(feature = "pco")] impl Traversable for vecdb::PcoVec where I: VecIndex, T: vecdb::PcoVecValue + Formattable + Serialize + JsonSchema, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } // LZ4Vec implementation (only if lz4 feature enabled) #[cfg(feature = "lz4")] impl Traversable for vecdb::LZ4Vec where I: VecIndex, T: vecdb::LZ4VecValue + Formattable + Serialize + JsonSchema, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } // ZstdVec implementation (only if zstd feature enabled) #[cfg(feature = "zstd")] impl Traversable for vecdb::ZstdVec where I: VecIndex, T: vecdb::ZstdVecValue + Formattable + Serialize + JsonSchema, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } // EagerVec implementation (wraps any stored vector) impl Traversable for EagerVec where V: StoredVec, V::T: Formattable + Serialize + JsonSchema, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } // Read-only compressed vec (PcoVec::ReadOnly, LZ4Vec::ReadOnly, ZstdVec::ReadOnly) impl Traversable for ReadOnlyCompressedVec where I: VecIndex, T: VecValue + Formattable + Serialize + JsonSchema, S: CompressionStrategy, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } // Read-only raw vec (BytesVec::ReadOnly, ZeroCopyVec::ReadOnly) impl Traversable for ReadOnlyRawVec where I: VecIndex, T: VecValue + Formattable + Serialize + JsonSchema, S: RawStrategy, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } impl Traversable for LazyVecFrom1 where I: VecIndex, T: VecValue + Formattable + Serialize + JsonSchema, S1I: VecIndex, S1T: VecValue, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } impl Traversable for LazyVecFrom2 where I: VecIndex, T: VecValue + Formattable + Serialize + JsonSchema, S1I: VecIndex, S1T: VecValue, S2I: VecIndex, S2T: VecValue, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } impl Traversable for LazyVecFrom3 where I: VecIndex, T: VecValue + Formattable + Serialize + JsonSchema, S1I: VecIndex, S1T: VecValue, S2I: VecIndex, S2T: VecValue, S3I: VecIndex, S3T: VecValue, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } impl Traversable for LazyAggVec where I: VecIndex, O: VecValue + Formattable + Serialize + JsonSchema, S1I: VecIndex, S2T: VecValue, S1T: VecValue, Strat: AggFold, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } impl Traversable for LazyDeltaVec where I: VecIndex, S: VecValue, T: VecValue + Formattable + Serialize + JsonSchema, Op: DeltaOp, { fn iter_any_exportable(&self) -> impl Iterator { std::iter::once(self as &dyn AnyExportableVec) } fn to_tree_node(&self) -> TreeNode { make_leaf::(self) } } impl Traversable for CachedVec { fn to_tree_node(&self) -> TreeNode { self.inner.to_tree_node() } fn iter_any_exportable(&self) -> impl Iterator { self.inner.iter_any_exportable() } fn iter_any_visible(&self) -> impl Iterator { self.inner.iter_any_visible() } } impl Traversable for Box { fn to_tree_node(&self) -> TreeNode { (**self).to_tree_node() } fn iter_any_exportable(&self) -> impl Iterator { (**self).iter_any_exportable() } fn iter_any_visible(&self) -> impl Iterator { (**self).iter_any_visible() } } impl Traversable for Option { fn to_tree_node(&self) -> TreeNode { match self { Some(inner) => inner.to_tree_node(), None => TreeNode::Branch(IndexMap::new()), } } fn iter_any_exportable(&self) -> impl Iterator { match self { Some(inner) => Box::new(inner.iter_any_exportable()) as Box>, None => Box::new(std::iter::empty()), } } fn iter_any_visible(&self) -> impl Iterator { match self { Some(inner) => Box::new(inner.iter_any_visible()) as Box>, None => Box::new(std::iter::empty()), } } } impl Traversable for BTreeMap { fn to_tree_node(&self) -> TreeNode { let children = self .iter() .map(|(k, v)| (format!("{}", k), v.to_tree_node())) .collect(); TreeNode::Branch(children) } fn iter_any_exportable(&self) -> impl Iterator { let mut iter: Box> = Box::new(std::iter::empty()); for v in self.values() { iter = Box::new(iter.chain(v.iter_any_exportable())); } iter } fn iter_any_visible(&self) -> impl Iterator { let mut iter: Box> = Box::new(std::iter::empty()); for v in self.values() { iter = Box::new(iter.chain(v.iter_any_visible())); } iter } } /// Unit type implementation - used as ZST placeholder for disabled features /// (e.g., Unpriced variants where dollar fields are not needed) impl Traversable for () { fn to_tree_node(&self) -> TreeNode { TreeNode::Branch(IndexMap::new()) } fn iter_any_exportable(&self) -> impl Iterator { std::iter::empty() } }