use std::{path::Path, time::Duration}; use brk_exit::Exit; use clap_derive::ValueEnum; use serde::{Deserialize, Serialize}; use brk_core::StoredPhantom; use crate::{ AnyCollectableVec, AnyIterableVec, AnyVec, BaseVecIterator, BoxedAnyIterableVec, BoxedVecIterator, CollectableVec, Compressed, Result, StoredIndex, StoredType, Value, Version, }; use super::{ ComputeFrom1, ComputeFrom2, ComputeFrom3, EagerVec, LazyVecFrom1, LazyVecFrom1Iterator, LazyVecFrom2, LazyVecFrom2Iterator, LazyVecFrom3, LazyVecFrom3Iterator, StoredVecIterator, }; #[derive( Default, Debug, PartialEq, PartialOrd, Ord, Eq, Clone, Copy, Serialize, Deserialize, ValueEnum, )] pub enum Computation { Eager, #[default] Lazy, } impl Computation { pub fn eager(&self) -> bool { *self == Self::Eager } pub fn lazy(&self) -> bool { *self == Self::Lazy } } #[derive(Clone)] pub enum Dependencies { From1(BoxedAnyIterableVec, ComputeFrom1), From2( (BoxedAnyIterableVec, BoxedAnyIterableVec), ComputeFrom2, ), From3( ( BoxedAnyIterableVec, BoxedAnyIterableVec, BoxedAnyIterableVec, ), ComputeFrom3, ), } pub type ComputedVecFrom1 = ComputedVec; pub type ComputedVecFrom2 = ComputedVec; pub type ComputedVecFrom3 = ComputedVec; #[derive(Clone)] pub enum ComputedVec { Eager { vec: EagerVec, deps: Dependencies, }, LazyFrom1(LazyVecFrom1), LazyFrom2(LazyVecFrom2), LazyFrom3(LazyVecFrom3), } impl ComputedVec where I: StoredIndex, T: StoredType, S1I: StoredIndex, S1T: StoredType, S2I: StoredIndex, S2T: StoredType, S3I: StoredIndex, S3T: StoredType, { pub fn forced_import_or_init_from_1( mode: Computation, path: &Path, name: &str, version: Version, compressed: Compressed, source: BoxedAnyIterableVec, compute: ComputeFrom1, ) -> Result { Ok(match mode { Computation::Eager => Self::Eager { vec: EagerVec::forced_import(path, version, compressed)?, deps: Dependencies::From1(source, compute), }, Computation::Lazy => { Self::LazyFrom1(LazyVecFrom1::init(name, version, source, compute)) } }) } #[allow(clippy::too_many_arguments)] pub fn forced_import_or_init_from_2( mode: Computation, path: &Path, name: &str, version: Version, compressed: Compressed, source1: BoxedAnyIterableVec, source2: BoxedAnyIterableVec, compute: ComputeFrom2, ) -> Result { Ok(match mode { Computation::Eager => Self::Eager { vec: EagerVec::forced_import(path, version, compressed)?, deps: Dependencies::From2((source1, source2), compute), }, Computation::Lazy => { Self::LazyFrom2(LazyVecFrom2::init(name, version, source1, source2, compute)) } }) } #[allow(clippy::too_many_arguments)] pub fn forced_import_or_init_from_3( mode: Computation, path: &Path, name: &str, version: Version, compressed: Compressed, source1: BoxedAnyIterableVec, source2: BoxedAnyIterableVec, source3: BoxedAnyIterableVec, compute: ComputeFrom3, ) -> Result { Ok(match mode { Computation::Eager => Self::Eager { vec: EagerVec::forced_import(path, version, compressed)?, deps: Dependencies::From3((source1, source2, source3), compute), }, Computation::Lazy => Self::LazyFrom3(LazyVecFrom3::init( name, version, source1, source2, source3, compute, )), }) } pub fn compute_if_necessary(&mut self, max_from: I, exit: &Exit) -> Result<()> { let (vec, dependencies) = if let ComputedVec::Eager { vec, deps: dependencies, } = self { (vec, dependencies) } else { return Ok(()); }; match dependencies { Dependencies::From1(source, compute) => { let version = source.version(); let mut iter = source.iter(); let t = |i: I| compute(i, &mut *iter).map(|v| (i, v)).unwrap(); vec.compute_to(max_from, 1, version, t, exit) } Dependencies::From2((source1, source2), compute) => { let version = source1.version() + source2.version(); let mut iter1 = source1.iter(); let mut iter2 = source2.iter(); let t = |i: I| { compute(i, &mut *iter1, &mut *iter2) .map(|v| (i, v)) .unwrap() }; vec.compute_to(max_from, 1, version, t, exit) } Dependencies::From3((source1, source2, source3), compute) => { let version = source1.version() + source2.version() + source3.version(); let mut iter1 = source1.iter(); let mut iter2 = source2.iter(); let mut iter3 = source3.iter(); let t = |i: I| { compute(i, &mut *iter1, &mut *iter2, &mut *iter3) .map(|v| (i, v)) .unwrap() }; vec.compute_to(max_from, 1, version, t, exit) } } } } impl AnyVec for ComputedVec where I: StoredIndex, T: StoredType, S1I: StoredIndex, S1T: StoredType, S2I: StoredIndex, S2T: StoredType, S3I: StoredIndex, S3T: StoredType, { fn version(&self) -> Version { match self { ComputedVec::Eager { vec, .. } => vec.version(), ComputedVec::LazyFrom1(v) => v.version(), ComputedVec::LazyFrom2(v) => v.version(), ComputedVec::LazyFrom3(v) => v.version(), } } fn name(&self) -> String { match self { ComputedVec::Eager { vec, .. } => vec.name(), ComputedVec::LazyFrom1(v) => v.name(), ComputedVec::LazyFrom2(v) => v.name(), ComputedVec::LazyFrom3(v) => v.name(), } } fn index_type_to_string(&self) -> &str { I::to_string() } fn len(&self) -> usize { match self { ComputedVec::Eager { vec, .. } => vec.len(), ComputedVec::LazyFrom1(v) => v.len(), ComputedVec::LazyFrom2(v) => v.len(), ComputedVec::LazyFrom3(v) => v.len(), } } fn modified_time(&self) -> Result { match self { ComputedVec::Eager { vec, .. } => vec.modified_time(), ComputedVec::LazyFrom1(v) => v.modified_time(), ComputedVec::LazyFrom2(v) => v.modified_time(), ComputedVec::LazyFrom3(v) => v.modified_time(), } } } pub enum ComputedVecIterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> { Eager(StoredVecIterator<'a, I, T>), LazyFrom1(LazyVecFrom1Iterator<'a, I, T, S1I, S1T>), LazyFrom2(LazyVecFrom2Iterator<'a, I, T, S1I, S1T, S2I, S2T>), LazyFrom3(LazyVecFrom3Iterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T>), } impl<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> Iterator for ComputedVecIterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> where I: StoredIndex, T: StoredType, S1I: StoredIndex, S1T: StoredType, S2I: StoredIndex, S2T: StoredType, S3I: StoredIndex, S3T: StoredType, { type Item = (I, Value<'a, T>); fn next(&mut self) -> Option { match self { Self::Eager(i) => i.next(), Self::LazyFrom1(i) => i.next(), Self::LazyFrom2(i) => i.next(), Self::LazyFrom3(i) => i.next(), } } } impl BaseVecIterator for ComputedVecIterator<'_, I, T, S1I, S1T, S2I, S2T, S3I, S3T> where I: StoredIndex, T: StoredType, S1I: StoredIndex, S1T: StoredType, S2I: StoredIndex, S2T: StoredType, S3I: StoredIndex, S3T: StoredType, { #[inline] fn mut_index(&mut self) -> &mut usize { match self { Self::Eager(i) => i.mut_index(), Self::LazyFrom1(i) => i.mut_index(), Self::LazyFrom2(i) => i.mut_index(), Self::LazyFrom3(i) => i.mut_index(), } } fn len(&self) -> usize { match self { Self::Eager(i) => i.len(), Self::LazyFrom1(i) => i.len(), Self::LazyFrom2(i) => i.len(), Self::LazyFrom3(i) => i.len(), } } } impl<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T> IntoIterator for &'a ComputedVec where I: StoredIndex, T: StoredType, S1I: StoredIndex, S1T: StoredType, S2I: StoredIndex, S2T: StoredType, S3I: StoredIndex, S3T: StoredType, { type Item = (I, Value<'a, T>); type IntoIter = ComputedVecIterator<'a, I, T, S1I, S1T, S2I, S2T, S3I, S3T>; fn into_iter(self) -> Self::IntoIter { match self { ComputedVec::Eager { vec, .. } => ComputedVecIterator::Eager(vec.into_iter()), ComputedVec::LazyFrom1(v) => ComputedVecIterator::LazyFrom1(v.into_iter()), ComputedVec::LazyFrom2(v) => ComputedVecIterator::LazyFrom2(v.into_iter()), ComputedVec::LazyFrom3(v) => ComputedVecIterator::LazyFrom3(v.into_iter()), } } } impl AnyIterableVec for ComputedVec where I: StoredIndex, T: StoredType, S1I: StoredIndex, S1T: StoredType, S2I: StoredIndex, S2T: StoredType, S3I: StoredIndex, S3T: StoredType, { fn boxed_iter<'a>(&'a self) -> BoxedVecIterator<'a, I, T> where T: 'a, { Box::new(self.into_iter()) } } impl AnyCollectableVec for ComputedVec where I: StoredIndex, T: StoredType, S1I: StoredIndex, S1T: StoredType, S2I: StoredIndex, S2T: StoredType, S3I: StoredIndex, S3T: StoredType, { fn collect_range_serde_json( &self, from: Option, to: Option, ) -> Result> { CollectableVec::collect_range_serde_json(self, from, to) } }