use std::sync::Arc;
use brk_traversable::{Traversable, TreeNode, make_leaf};
use schemars::JsonSchema;
use serde::Serialize;
use vecdb::{
AnyExportableVec, AnyVec, CachedBoxedVec, Formattable, ReadableBoxedVec, ReadableVec, TypedVec,
VecIndex, VecValue, Version, short_type_name,
};
pub struct LazyIndexedVec<I, S, M, T>
where
I: VecIndex,
S: VecValue,
M: VecValue,
T: VecValue,
{
name: Arc<str>,
base_version: Version,
source: ReadableBoxedVec<I, S>,
metadata: CachedBoxedVec<I, M>,
compute: Arc<dyn Fn(I, S, M) -> T + Send + Sync>,
}
impl<I, S, M, T> LazyIndexedVec<I, S, M, T>
where
I: VecIndex,
S: VecValue,
M: VecValue,
T: VecValue,
{
pub fn new(
name: &str,
version: Version,
source: ReadableBoxedVec<I, S>,
metadata: CachedBoxedVec<I, M>,
compute: impl Fn(I, S, M) -> T + Send + Sync + 'static,
) -> Self {
Self {
name: Arc::from(name),
base_version: version,
source,
metadata,
compute: Arc::new(compute),
}
}
fn for_each_value(&self, from: usize, to: usize, mut each: impl FnMut(T)) {
let metadata = self.metadata.cached();
let to = to.min(self.len()).min(metadata.len());
if from >= to {
return;
}
let source = self.source.collect_range_dyn(from, to);
for (offset, (source, metadata)) in source
.into_iter()
.zip(metadata[from..to].iter().cloned())
.enumerate()
{
each((self.compute)(I::from(from + offset), source, metadata));
}
}
}
impl<I, S, M, T> Clone for LazyIndexedVec<I, S, M, T>
where
I: VecIndex,
S: VecValue,
M: VecValue,
T: VecValue,
{
fn clone(&self) -> Self {
Self {
name: Arc::clone(&self.name),
base_version: self.base_version,
source: self.source.clone(),
metadata: self.metadata.clone(),
compute: Arc::clone(&self.compute),
}
}
}
impl<I, S, M, T> AnyVec for LazyIndexedVec<I, S, M, T>
where
I: VecIndex,
S: VecValue,
M: VecValue,
T: VecValue,
{
fn version(&self) -> Version {
self.base_version + self.source.version() + self.metadata.version()
}
fn name(&self) -> &str {
&self.name
}
fn index_type_to_string(&self) -> &'static str {
I::to_string()
}
fn len(&self) -> usize {
self.source.len().min(self.metadata.len())
}
fn value_type_to_size_of(&self) -> usize {
size_of::<T>()
}
fn value_type_to_string(&self) -> &'static str {
short_type_name::<T>()
}
fn region_names(&self) -> Vec<String> {
Vec::new()
}
}
impl<I, S, M, T> TypedVec for LazyIndexedVec<I, S, M, T>
where
I: VecIndex,
S: VecValue,
M: VecValue,
T: VecValue,
{
type I = I;
type T = T;
}
impl<I, S, M, T> ReadableVec<I, T> for LazyIndexedVec<I, S, M, T>
where
I: VecIndex,
S: VecValue,
M: VecValue,
T: VecValue,
{
fn read_into_at(&self, from: usize, to: usize, buf: &mut Vec<T>) {
buf.reserve(to.saturating_sub(from));
self.for_each_value(from, to, |value| buf.push(value));
}
fn for_each_range_dyn_at(&self, from: usize, to: usize, f: &mut dyn FnMut(T)) {
self.for_each_value(from, to, f);
}
fn fold_range_at<B, F: FnMut(B, T) -> B>(&self, from: usize, to: usize, init: B, f: F) -> B {
let mut values = Vec::with_capacity(to.saturating_sub(from));
self.read_into_at(from, to, &mut values);
values.into_iter().fold(init, f)
}
fn try_fold_range_at<B, E, F: FnMut(B, T) -> Result<B, E>>(
&self,
from: usize,
to: usize,
init: B,
f: F,
) -> Result<B, E> {
let mut values = Vec::with_capacity(to.saturating_sub(from));
self.read_into_at(from, to, &mut values);
values.into_iter().try_fold(init, f)
}
fn collect_one_at(&self, index: usize) -> Option<T> {
let source = self.source.collect_one_at(index)?;
let metadata = self.metadata.cached().get(index)?.clone();
Some((self.compute)(I::from(index), source, metadata))
}
fn read_sorted_into_at(&self, indices: &[usize], out: &mut Vec<T>) {
out.reserve(indices.len());
indices
.iter()
.filter_map(|&index| self.collect_one_at(index))
.for_each(|value| out.push(value));
}
}
impl<I, S, M, T> Traversable for LazyIndexedVec<I, S, M, T>
where
I: VecIndex,
S: VecValue,
M: VecValue,
T: VecValue + Formattable + Serialize + JsonSchema,
{
fn iter_any_exportable(&self) -> impl Iterator<Item = &dyn AnyExportableVec> {
std::iter::once(self as &dyn AnyExportableVec)
}
fn to_tree_node(&self) -> TreeNode {
make_leaf::<I, T, _>(self)
}
}