mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-26 15:49:58 -07:00
computer: convert stores to vecs part 1
This commit is contained in:
474
crates/brk_computer/src/grouped/builder_computed.rs
Normal file
474
crates/brk_computer/src/grouped/builder_computed.rs
Normal file
@@ -0,0 +1,474 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{FromCoarserIndex, Result, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyIterableVec, BoxedAnyIterableVec, CloneableAnyIterableVec, Computation,
|
||||
ComputedVec, ComputedVecFrom2, Format, StoredIndex,
|
||||
};
|
||||
|
||||
use crate::grouped::{EagerVecBuilder, VecBuilderOptions};
|
||||
|
||||
use super::ComputedType;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecBuilder<I, T, S1I, S2T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
S2T: ComputedType,
|
||||
{
|
||||
pub first: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub average: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub sum: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub max: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub min: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub last: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub cumulative: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<I, T, S1I, S2T> ComputedVecBuilder<I, T, S1I, S2T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType + 'static,
|
||||
S1I: StoredIndex + 'static + FromCoarserIndex<I>,
|
||||
S2T: ComputedType,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
format: Format,
|
||||
computation: Computation,
|
||||
source: Option<BoxedAnyIterableVec<S1I, T>>,
|
||||
source_extra: &EagerVecBuilder<S1I, T>,
|
||||
len_source: BoxedAnyIterableVec<I, S2T>,
|
||||
options: ComputedVecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
let suffix = |s: &str| format!("{name}_{s}");
|
||||
|
||||
let maybe_suffix = |s: &str| {
|
||||
if only_one_active {
|
||||
name.to_string()
|
||||
} else {
|
||||
suffix(s)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
first: options.first.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&maybe_suffix("first"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.first
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
source
|
||||
.next_at(S1I::min_from(i))
|
||||
.map(|(_, cow)| cow.into_owned())
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
last: options.last.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra.last.as_ref().map_or_else(
|
||||
|| {
|
||||
source
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| {
|
||||
dbg!(path, name, I::to_string());
|
||||
panic!()
|
||||
})
|
||||
.clone()
|
||||
},
|
||||
|v| v.clone(),
|
||||
),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
source
|
||||
.next_at(S1I::max_from(i, source.len()))
|
||||
.map(|(_, cow)| cow.into_owned())
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
min: options.min.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&maybe_suffix("min"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.min
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
S1I::inclusive_range_from(i, source.len())
|
||||
.flat_map(|i| source.next_at(i).map(|(_, cow)| cow.into_owned()))
|
||||
.min()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
max: options.max.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&maybe_suffix("max"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.max
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
S1I::inclusive_range_from(i, source.len())
|
||||
.flat_map(|i| source.next_at(i).map(|(_, cow)| cow.into_owned()))
|
||||
.max()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
average: options.average.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&maybe_suffix("average"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.average
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
let vec = S1I::inclusive_range_from(i, source.len())
|
||||
.flat_map(|i| source.next_at(i).map(|(_, cow)| cow.into_owned()))
|
||||
.collect::<Vec<_>>();
|
||||
if vec.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut sum = T::from(0);
|
||||
let len = vec.len();
|
||||
vec.into_iter().for_each(|v| sum += v);
|
||||
Some(sum / len)
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
sum: options.sum.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&(if !options.last && !options.average && !options.min && !options.max {
|
||||
name.to_string()
|
||||
} else {
|
||||
maybe_suffix("sum")
|
||||
}),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.sum
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
let vec = S1I::inclusive_range_from(i, source.len())
|
||||
.flat_map(|i| source.next_at(i).map(|(_, cow)| cow.into_owned()))
|
||||
.collect::<Vec<_>>();
|
||||
if vec.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut sum = T::from(0);
|
||||
vec.into_iter().for_each(|v| sum += v);
|
||||
Some(sum)
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
cumulative: options.cumulative.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&suffix("cumulative"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra.cumulative.as_ref().unwrap().boxed_clone(),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
source
|
||||
.next_at(S1I::max_from(i, source.len()))
|
||||
.map(|(_, cow)| cow.into_owned())
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_if_necessary<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
len_source: &impl AnyIterableVec<I, T2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_mut() {
|
||||
cumulative.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn starting_index(&self, max_from: I) -> I {
|
||||
max_from.min(I::from(
|
||||
self.vecs().into_iter().map(|v| v.len()).min().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn unwrap_first(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.first.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_average(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.average.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_sum(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.sum.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_max(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.max.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_min(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.min.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_last(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.last.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_cumulative(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.cumulative.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
let mut v: Vec<&dyn AnyCollectableVec> = vec![];
|
||||
|
||||
if let Some(first) = self.first.as_ref() {
|
||||
v.push(first.as_ref());
|
||||
}
|
||||
if let Some(last) = self.last.as_ref() {
|
||||
v.push(last.as_ref());
|
||||
}
|
||||
if let Some(min) = self.min.as_ref() {
|
||||
v.push(min.as_ref());
|
||||
}
|
||||
if let Some(max) = self.max.as_ref() {
|
||||
v.push(max.as_ref());
|
||||
}
|
||||
if let Some(average) = self.average.as_ref() {
|
||||
v.push(average.as_ref());
|
||||
}
|
||||
if let Some(sum) = self.sum.as_ref() {
|
||||
v.push(sum.as_ref());
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_ref() {
|
||||
v.push(cumulative.as_ref());
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct ComputedVecBuilderOptions {
|
||||
average: bool,
|
||||
sum: bool,
|
||||
max: bool,
|
||||
min: bool,
|
||||
first: bool,
|
||||
last: bool,
|
||||
cumulative: bool,
|
||||
}
|
||||
|
||||
impl From<VecBuilderOptions> for ComputedVecBuilderOptions {
|
||||
fn from(value: VecBuilderOptions) -> Self {
|
||||
Self {
|
||||
average: value.average(),
|
||||
sum: value.sum(),
|
||||
max: value.max(),
|
||||
min: value.min(),
|
||||
first: value.first(),
|
||||
last: value.last(),
|
||||
cumulative: value.cumulative(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedVecBuilderOptions {
|
||||
pub fn add_first(mut self) -> Self {
|
||||
self.first = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_last(mut self) -> Self {
|
||||
self.last = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_min(mut self) -> Self {
|
||||
self.min = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_max(mut self) -> Self {
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_average(mut self) -> Self {
|
||||
self.average = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_sum(mut self) -> Self {
|
||||
self.sum = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_cumulative(mut self) -> Self {
|
||||
self.cumulative = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_min(mut self) -> Self {
|
||||
self.min = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_max(mut self) -> Self {
|
||||
self.max = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_average(mut self) -> Self {
|
||||
self.average = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_sum(mut self) -> Self {
|
||||
self.sum = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_cumulative(mut self) -> Self {
|
||||
self.cumulative = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_minmax(mut self) -> Self {
|
||||
self.min = true;
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_only_one_active(&self) -> bool {
|
||||
[
|
||||
self.average,
|
||||
self.sum,
|
||||
self.max,
|
||||
self.min,
|
||||
self.first,
|
||||
self.last,
|
||||
self.cumulative,
|
||||
]
|
||||
.iter()
|
||||
.filter(|b| **b)
|
||||
.count()
|
||||
== 1
|
||||
}
|
||||
|
||||
pub fn copy_self_extra(&self) -> Self {
|
||||
Self {
|
||||
cumulative: self.cumulative,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
949
crates/brk_computer/src/grouped/builder_eager.rs
Normal file
949
crates/brk_computer/src/grouped/builder_eager.rs
Normal file
@@ -0,0 +1,949 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{CheckedSub, Result, StoredUsize, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format, StoredIndex, StoredType};
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
|
||||
use crate::utils::get_percentile;
|
||||
|
||||
use super::ComputedType;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EagerVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub first: Option<Box<EagerVec<I, T>>>,
|
||||
pub average: Option<Box<EagerVec<I, T>>>,
|
||||
pub sum: Option<Box<EagerVec<I, T>>>,
|
||||
pub max: Option<Box<EagerVec<I, T>>>,
|
||||
pub _90p: Option<Box<EagerVec<I, T>>>,
|
||||
pub _75p: Option<Box<EagerVec<I, T>>>,
|
||||
pub median: Option<Box<EagerVec<I, T>>>,
|
||||
pub _25p: Option<Box<EagerVec<I, T>>>,
|
||||
pub _10p: Option<Box<EagerVec<I, T>>>,
|
||||
pub min: Option<Box<EagerVec<I, T>>>,
|
||||
pub last: Option<Box<EagerVec<I, T>>>,
|
||||
pub cumulative: Option<Box<EagerVec<I, T>>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<I, T> EagerVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
let suffix = |s: &str| format!("{name}_{s}");
|
||||
|
||||
let maybe_suffix = |s: &str| {
|
||||
if only_one_active {
|
||||
name.to_string()
|
||||
} else {
|
||||
suffix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let s = Self {
|
||||
first: options.first.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("first"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
last: options.last.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(path, name, version + Version::ZERO, format).unwrap(),
|
||||
)
|
||||
}),
|
||||
min: options.min.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("min"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
max: options.max.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("max"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
median: options.median.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("median"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
average: options.average.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("average"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
sum: options.sum.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&(if !options.last && !options.average && !options.min && !options.max {
|
||||
name.to_string()
|
||||
} else {
|
||||
maybe_suffix("sum")
|
||||
}),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
cumulative: options.cumulative.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&suffix("cumulative"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
_90p: options._90p.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("90p"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
_75p: options._75p.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("75p"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
_25p: options._25p.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("25p"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
_10p: options._10p.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("10p"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
};
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub fn extend(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &impl AnyIterableVec<I, T>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
if self.cumulative.is_none() {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
self.validate_computed_version_or_reset_file(source.version())?;
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let cumulative_vec = self.cumulative.as_mut().unwrap();
|
||||
|
||||
let mut cumulative = index.decremented().map_or(T::from(0_usize), |index| {
|
||||
cumulative_vec.iter().unwrap_get_inner(index)
|
||||
});
|
||||
source.iter_at(index).try_for_each(|(i, v)| -> Result<()> {
|
||||
cumulative = cumulative.clone() + v.into_owned();
|
||||
cumulative_vec.forced_push_at(i, cumulative.clone(), exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &impl AnyIterableVec<I2, T>,
|
||||
first_indexes: &impl AnyIterableVec<I, I2>,
|
||||
count_indexes: &impl AnyIterableVec<I, StoredUsize>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType + CheckedSub<I2>,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
source.version() + first_indexes.version() + count_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let mut count_indexes_iter = count_indexes.iter();
|
||||
let mut source_iter = source.iter();
|
||||
|
||||
let cumulative_vec = self.cumulative.as_mut();
|
||||
|
||||
let mut cumulative = cumulative_vec.map(|cumulative_vec| {
|
||||
index.decremented().map_or(T::from(0_usize), |index| {
|
||||
cumulative_vec.iter().unwrap_get_inner(index)
|
||||
})
|
||||
});
|
||||
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index)| -> Result<()> {
|
||||
let first_index = first_index.into_owned();
|
||||
|
||||
let count_index = count_indexes_iter.unwrap_get_inner(i);
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let f = source_iter
|
||||
.get_inner(first_index)
|
||||
.unwrap_or_else(|| T::from(0_usize));
|
||||
first.forced_push_at(index, f, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let count_index = *count_index;
|
||||
if count_index == 0 {
|
||||
panic!("should compute last if count can be 0")
|
||||
}
|
||||
let last_index = first_index + (count_index - 1);
|
||||
let v = source_iter.unwrap_get_inner(last_index);
|
||||
// .context("to work")
|
||||
// .inspect_err(|_| {
|
||||
// dbg!(first_index, count_index, last_index);
|
||||
// })
|
||||
// .unwrap()
|
||||
// .into_owned();
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let needs_sum_or_cumulative = self.sum.is_some() || self.cumulative.is_some();
|
||||
let needs_average_sum_or_cumulative =
|
||||
needs_sum_or_cumulative || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some()
|
||||
|| self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
|| self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_average_sum_or_cumulative;
|
||||
|
||||
if needs_values {
|
||||
source_iter.set(first_index);
|
||||
let mut values = (&mut source_iter)
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if needs_sorted {
|
||||
values.sort_unstable();
|
||||
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.forced_push_at(
|
||||
i,
|
||||
values
|
||||
.last()
|
||||
.context("expect some")
|
||||
.inspect_err(|_| {
|
||||
dbg!(
|
||||
&values,
|
||||
max.path(),
|
||||
first_indexes.name(),
|
||||
first_index,
|
||||
count_indexes.name(),
|
||||
count_index,
|
||||
source.len(),
|
||||
source.name()
|
||||
);
|
||||
})
|
||||
.unwrap()
|
||||
.clone(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.forced_push_at(i, get_percentile(&values, 0.90), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.forced_push_at(i, get_percentile(&values, 0.75), exit)?;
|
||||
}
|
||||
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.forced_push_at(i, get_percentile(&values, 0.50), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.forced_push_at(i, get_percentile(&values, 0.25), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.forced_push_at(i, get_percentile(&values, 0.10), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_average_sum_or_cumulative {
|
||||
let len = values.len();
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let avg = sum.clone() / len;
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_cumulative {
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(cumulative_vec) = self.cumulative.as_mut() {
|
||||
let t = cumulative.as_ref().unwrap().clone() + sum;
|
||||
cumulative.replace(t.clone());
|
||||
cumulative_vec.forced_push_at(i, t, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_aligned<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &EagerVecBuilder<I2, T>,
|
||||
first_indexes: &impl AnyIterableVec<I, I2>,
|
||||
count_indexes: &impl AnyIterableVec<I, StoredUsize>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType + CheckedSub<I2>,
|
||||
{
|
||||
if self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
{
|
||||
panic!("unsupported");
|
||||
}
|
||||
|
||||
self.validate_computed_version_or_reset_file(
|
||||
VERSION + first_indexes.version() + count_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let mut count_indexes_iter = count_indexes.iter();
|
||||
|
||||
let mut source_first_iter = source.first.as_ref().map(|f| f.iter());
|
||||
let mut source_last_iter = source.last.as_ref().map(|f| f.iter());
|
||||
let mut source_max_iter = source.max.as_ref().map(|f| f.iter());
|
||||
let mut source_min_iter = source.min.as_ref().map(|f| f.iter());
|
||||
let mut source_average_iter = source.average.as_ref().map(|f| f.iter());
|
||||
let mut source_sum_iter = source.sum.as_ref().map(|f| f.iter());
|
||||
|
||||
let mut cumulative = self.cumulative.as_mut().map(|cumulative_vec| {
|
||||
index.decremented().map_or(T::from(0_usize), |index| {
|
||||
cumulative_vec.iter().unwrap_get_inner(index)
|
||||
})
|
||||
});
|
||||
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index, ..)| -> Result<()> {
|
||||
let first_index = first_index.into_owned();
|
||||
|
||||
let count_index = count_indexes_iter.unwrap_get_inner(i);
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let v = source_first_iter
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.unwrap_get_inner(first_index);
|
||||
first.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let count_index = *count_index;
|
||||
if count_index == 0 {
|
||||
panic!("should compute last if count can be 0")
|
||||
}
|
||||
let last_index = first_index + (count_index - 1);
|
||||
let v = source_last_iter
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.unwrap_get_inner(last_index);
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let needs_sum_or_cumulative = self.sum.is_some() || self.cumulative.is_some();
|
||||
let needs_average_sum_or_cumulative =
|
||||
needs_sum_or_cumulative || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some() || self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_average_sum_or_cumulative;
|
||||
|
||||
if needs_values {
|
||||
if needs_sorted {
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
let source_max_iter = source_max_iter.as_mut().unwrap();
|
||||
source_max_iter.set(first_index);
|
||||
let mut values = source_max_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
values.sort_unstable();
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
let source_min_iter = source_min_iter.as_mut().unwrap();
|
||||
source_min_iter.set(first_index);
|
||||
let mut values = source_min_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
values.sort_unstable();
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_average_sum_or_cumulative {
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let source_average_iter = source_average_iter.as_mut().unwrap();
|
||||
source_average_iter.set(first_index);
|
||||
let values = source_average_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let len = values.len();
|
||||
let cumulative = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
// TODO: Multiply by count then divide by cumulative
|
||||
// Right now it's not 100% accurate as there could be more or less elements in the lower timeframe (28 days vs 31 days in a month for example)
|
||||
let avg = cumulative / len;
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_cumulative {
|
||||
let source_sum_iter = source_sum_iter.as_mut().unwrap();
|
||||
source_sum_iter.set(first_index);
|
||||
let values = source_sum_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(cumulative_vec) = self.cumulative.as_mut() {
|
||||
let t = cumulative.as_ref().unwrap().clone() + sum;
|
||||
cumulative.replace(t.clone());
|
||||
cumulative_vec.forced_push_at(i, t, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn starting_index(&self, max_from: I) -> I {
|
||||
max_from.min(I::from(
|
||||
self.vecs().into_iter().map(|v| v.len()).min().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn unwrap_first(&self) -> &EagerVec<I, T> {
|
||||
self.first.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_average(&self) -> &EagerVec<I, T> {
|
||||
self.average.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_sum(&self) -> &EagerVec<I, T> {
|
||||
self.sum.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_max(&self) -> &EagerVec<I, T> {
|
||||
self.max.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_90p(&self) -> &EagerVec<I, T> {
|
||||
self._90p.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_75p(&self) -> &EagerVec<I, T> {
|
||||
self._75p.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_median(&self) -> &EagerVec<I, T> {
|
||||
self.median.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_25p(&self) -> &EagerVec<I, T> {
|
||||
self._25p.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_10p(&self) -> &EagerVec<I, T> {
|
||||
self._10p.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_min(&self) -> &EagerVec<I, T> {
|
||||
self.min.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_last(&self) -> &EagerVec<I, T> {
|
||||
self.last.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_cumulative(&self) -> &EagerVec<I, T> {
|
||||
self.cumulative.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
let mut v: Vec<&dyn AnyCollectableVec> = vec![];
|
||||
|
||||
if let Some(first) = self.first.as_ref() {
|
||||
v.push(first.as_ref());
|
||||
}
|
||||
if let Some(last) = self.last.as_ref() {
|
||||
v.push(last.as_ref());
|
||||
}
|
||||
if let Some(min) = self.min.as_ref() {
|
||||
v.push(min.as_ref());
|
||||
}
|
||||
if let Some(max) = self.max.as_ref() {
|
||||
v.push(max.as_ref());
|
||||
}
|
||||
if let Some(median) = self.median.as_ref() {
|
||||
v.push(median.as_ref());
|
||||
}
|
||||
if let Some(average) = self.average.as_ref() {
|
||||
v.push(average.as_ref());
|
||||
}
|
||||
if let Some(sum) = self.sum.as_ref() {
|
||||
v.push(sum.as_ref());
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_ref() {
|
||||
v.push(cumulative.as_ref());
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_ref() {
|
||||
v.push(_90p.as_ref());
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_ref() {
|
||||
v.push(_75p.as_ref());
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_ref() {
|
||||
v.push(_25p.as_ref());
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_ref() {
|
||||
v.push(_10p.as_ref());
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_mut() {
|
||||
cumulative.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.safe_flush(exit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_computed_version_or_reset_file(&mut self, version: Version) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_mut() {
|
||||
cumulative.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct VecBuilderOptions {
|
||||
average: bool,
|
||||
sum: bool,
|
||||
max: bool,
|
||||
_90p: bool,
|
||||
_75p: bool,
|
||||
median: bool,
|
||||
_25p: bool,
|
||||
_10p: bool,
|
||||
min: bool,
|
||||
first: bool,
|
||||
last: bool,
|
||||
cumulative: bool,
|
||||
}
|
||||
|
||||
impl VecBuilderOptions {
|
||||
pub fn average(&self) -> bool {
|
||||
self.average
|
||||
}
|
||||
|
||||
pub fn sum(&self) -> bool {
|
||||
self.sum
|
||||
}
|
||||
|
||||
pub fn max(&self) -> bool {
|
||||
self.max
|
||||
}
|
||||
|
||||
pub fn _90p(&self) -> bool {
|
||||
self._90p
|
||||
}
|
||||
|
||||
pub fn _75p(&self) -> bool {
|
||||
self._75p
|
||||
}
|
||||
|
||||
pub fn median(&self) -> bool {
|
||||
self.median
|
||||
}
|
||||
|
||||
pub fn _25p(&self) -> bool {
|
||||
self._25p
|
||||
}
|
||||
|
||||
pub fn _10p(&self) -> bool {
|
||||
self._10p
|
||||
}
|
||||
|
||||
pub fn min(&self) -> bool {
|
||||
self.min
|
||||
}
|
||||
|
||||
pub fn first(&self) -> bool {
|
||||
self.first
|
||||
}
|
||||
|
||||
pub fn last(&self) -> bool {
|
||||
self.last
|
||||
}
|
||||
|
||||
pub fn cumulative(&self) -> bool {
|
||||
self.cumulative
|
||||
}
|
||||
|
||||
pub fn add_first(mut self) -> Self {
|
||||
self.first = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_last(mut self) -> Self {
|
||||
self.last = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_min(mut self) -> Self {
|
||||
self.min = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_max(mut self) -> Self {
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_median(mut self) -> Self {
|
||||
self.median = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_average(mut self) -> Self {
|
||||
self.average = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_sum(mut self) -> Self {
|
||||
self.sum = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_90p(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_75p(mut self) -> Self {
|
||||
self._75p = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_25p(mut self) -> Self {
|
||||
self._25p = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_10p(mut self) -> Self {
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_cumulative(mut self) -> Self {
|
||||
self.cumulative = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_min(mut self) -> Self {
|
||||
self.min = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_max(mut self) -> Self {
|
||||
self.max = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_median(mut self) -> Self {
|
||||
self.median = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_average(mut self) -> Self {
|
||||
self.average = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_sum(mut self) -> Self {
|
||||
self.sum = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_90p(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_75p(mut self) -> Self {
|
||||
self._75p = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_25p(mut self) -> Self {
|
||||
self._25p = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_10p(mut self) -> Self {
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_cumulative(mut self) -> Self {
|
||||
self.cumulative = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_minmax(mut self) -> Self {
|
||||
self.min = true;
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_percentiles(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self._75p = true;
|
||||
self.median = true;
|
||||
self._25p = true;
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn remove_percentiles(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self._75p = false;
|
||||
self.median = false;
|
||||
self._25p = false;
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_only_one_active(&self) -> bool {
|
||||
[
|
||||
self.average,
|
||||
self.sum,
|
||||
self.max,
|
||||
self._90p,
|
||||
self._75p,
|
||||
self.median,
|
||||
self._25p,
|
||||
self._10p,
|
||||
self.min,
|
||||
self.first,
|
||||
self.last,
|
||||
self.cumulative,
|
||||
]
|
||||
.iter()
|
||||
.filter(|b| **b)
|
||||
.count()
|
||||
== 1
|
||||
}
|
||||
|
||||
pub fn copy_self_extra(&self) -> Self {
|
||||
Self {
|
||||
cumulative: self.cumulative,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
239
crates/brk_computer/src/grouped/from_dateindex.rs
Normal file
239
crates/brk_computer/src/grouped/from_dateindex.rs
Normal file
@@ -0,0 +1,239 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, Result, SemesterIndex, Version, WeekIndex,
|
||||
YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyIterableVec, CloneableAnyIterableVec, Computation, EagerVec, Format,
|
||||
};
|
||||
|
||||
use crate::{Indexes, grouped::ComputedVecBuilder, indexes};
|
||||
|
||||
use super::{ComputedType, EagerVecBuilder, Source, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromDateIndex<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub dateindex: Option<EagerVec<DateIndex, T>>,
|
||||
pub dateindex_extra: EagerVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
|
||||
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromDateIndex<T>
|
||||
where
|
||||
T: ComputedType + 'static,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
source: Source<DateIndex, T>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
computation: Computation,
|
||||
indexes: &indexes::Vecs,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let dateindex = source.is_compute().then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format).unwrap()
|
||||
});
|
||||
|
||||
let dateindex_extra = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
let dateindex_source = source.vec().or(dateindex.as_ref().map(|v| v.boxed_clone()));
|
||||
|
||||
Ok(Self {
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
computation,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.weekindex_to_weekindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.monthindex_to_monthindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.quarterindex_to_quarterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
semesterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.semesterindex_to_semesterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.yearindex_to_yearindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.decadeindex_to_decadeindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
dateindex,
|
||||
dateindex_extra,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<DateIndex, T>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.dateindex.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let dateindex: Option<&EagerVec<DateIndex, T>> = None;
|
||||
self.compute_rest(indexes, starting_indexes, exit, dateindex)
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
dateindex: Option<&impl AnyIterableVec<DateIndex, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(dateindex) = dateindex {
|
||||
self.dateindex_extra
|
||||
.extend(starting_indexes.dateindex, dateindex, exit)?;
|
||||
} else {
|
||||
let dateindex = self.dateindex.as_ref().unwrap();
|
||||
|
||||
self.dateindex_extra
|
||||
.extend(starting_indexes.dateindex, dateindex, exit)?;
|
||||
}
|
||||
|
||||
self.weekindex.compute_if_necessary(
|
||||
starting_indexes.weekindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute_if_necessary(
|
||||
starting_indexes.monthindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.compute_if_necessary(
|
||||
starting_indexes.quarterindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.semesterindex.compute_if_necessary(
|
||||
starting_indexes.semesterindex,
|
||||
&indexes.semesterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.compute_if_necessary(
|
||||
starting_indexes.yearindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.compute_if_necessary(
|
||||
starting_indexes.decadeindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.dateindex
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| vec![v as &dyn AnyCollectableVec]),
|
||||
self.dateindex_extra.vecs(),
|
||||
self.weekindex.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.semesterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
291
crates/brk_computer/src/grouped/from_height.rs
Normal file
291
crates/brk_computer/src/grouped/from_height.rs
Normal file
@@ -0,0 +1,291 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, Result,
|
||||
SemesterIndex, Version, WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyIterableVec, CloneableAnyIterableVec, Computation, EagerVec, Format,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecBuilder, Source},
|
||||
indexes,
|
||||
};
|
||||
|
||||
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: Option<EagerVec<Height, T>>,
|
||||
pub height_extra: EagerVecBuilder<Height, T>,
|
||||
pub dateindex: EagerVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
|
||||
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
|
||||
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64> + 'static,
|
||||
f64: From<T>,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
source: Source<Height, T>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
computation: Computation,
|
||||
indexes: &indexes::Vecs,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let height = source.is_compute().then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format).unwrap()
|
||||
});
|
||||
|
||||
let height_extra = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let dateindex = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
computation,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.weekindex_to_weekindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.monthindex_to_monthindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.quarterindex_to_quarterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
semesterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.semesterindex_to_semesterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.yearindex_to_yearindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.decadeindex_to_decadeindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
|
||||
height,
|
||||
height_extra,
|
||||
dateindex,
|
||||
difficultyepoch: EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.height.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let height: Option<&EagerVec<Height, T>> = None;
|
||||
self.compute_rest(indexes, starting_indexes, exit, height)
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height_vec: Option<&impl AnyIterableVec<Height, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height_vec {
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, height, exit)?;
|
||||
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
height,
|
||||
&indexes.dateindex_to_first_height,
|
||||
&indexes.dateindex_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
height,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
&indexes.difficultyepoch_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
} else {
|
||||
let height = self.height.as_ref().unwrap();
|
||||
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, height, exit)?;
|
||||
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
height,
|
||||
&indexes.dateindex_to_first_height,
|
||||
&indexes.dateindex_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
height,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
&indexes.difficultyepoch_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.weekindex.compute_if_necessary(
|
||||
starting_indexes.weekindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute_if_necessary(
|
||||
starting_indexes.monthindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.compute_if_necessary(
|
||||
starting_indexes.quarterindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.semesterindex.compute_if_necessary(
|
||||
starting_indexes.semesterindex,
|
||||
&indexes.semesterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.compute_if_necessary(
|
||||
starting_indexes.yearindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.compute_if_necessary(
|
||||
starting_indexes.decadeindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.height
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| vec![v as &dyn AnyCollectableVec]),
|
||||
self.height_extra.vecs(),
|
||||
self.dateindex.vecs(),
|
||||
self.weekindex.vecs(),
|
||||
self.difficultyepoch.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.semesterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
// self.halvingepoch.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
102
crates/brk_computer/src/grouped/from_height_strict.rs
Normal file
102
crates/brk_computer/src/grouped/from_height_strict.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{DifficultyEpoch, Height, Result, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, EagerVec, Format};
|
||||
|
||||
use crate::{Indexes, indexes};
|
||||
|
||||
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: EagerVec<Height, T>,
|
||||
pub height_extra: EagerVecBuilder<Height, T>,
|
||||
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let height =
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)?;
|
||||
|
||||
let height_extra = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
height,
|
||||
height_extra,
|
||||
difficultyepoch: EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
|
||||
{
|
||||
compute(&mut self.height, indexer, indexes, starting_indexes, exit)?;
|
||||
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, &self.height, exit)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
&self.height,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
&indexes.difficultyepoch_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
vec![&self.height as &dyn AnyCollectableVec],
|
||||
self.height_extra.vecs(),
|
||||
self.difficultyepoch.vecs(),
|
||||
// self.halvingepoch.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
669
crates/brk_computer/src/grouped/from_txindex.rs
Normal file
669
crates/brk_computer/src/grouped/from_txindex.rs
Normal file
@@ -0,0 +1,669 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
Bitcoin, DateIndex, DecadeIndex, DifficultyEpoch, Dollars, Height, MonthIndex, QuarterIndex,
|
||||
Result, Sats, SemesterIndex, TxIndex, Version, WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyVec, CloneableAnyIterableVec, CollectableVec, Computation, EagerVec,
|
||||
Format, StoredIndex, VecIterator,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Indexes, fetched,
|
||||
grouped::{ComputedVecBuilder, Source},
|
||||
indexes,
|
||||
};
|
||||
|
||||
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromTxindex<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub txindex: Option<Box<EagerVec<TxIndex, T>>>,
|
||||
pub height: EagerVecBuilder<Height, T>,
|
||||
pub dateindex: EagerVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
|
||||
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
|
||||
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromTxindex<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64> + 'static,
|
||||
f64: From<T>,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
source: Source<TxIndex, T>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
computation: Computation,
|
||||
indexes: &indexes::Vecs,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let txindex = source.is_compute().then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let height = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
let dateindex = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
computation,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.weekindex_to_weekindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.monthindex_to_monthindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.quarterindex_to_quarterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
semesterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.semesterindex_to_semesterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.yearindex_to_yearindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.decadeindex_to_decadeindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
|
||||
txindex,
|
||||
height,
|
||||
dateindex,
|
||||
difficultyepoch: EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
// #[allow(unused)]
|
||||
// pub fn compute_all<F>(
|
||||
// &mut self,
|
||||
// indexer: &Indexer,
|
||||
// indexes: &indexes::Vecs,
|
||||
// starting_indexes: &Indexes,
|
||||
// exit: &Exit,
|
||||
// mut compute: F,
|
||||
// ) -> color_eyre::Result<()>
|
||||
// where
|
||||
// F: FnMut(
|
||||
// &mut EagerVec<TxIndex, T>,
|
||||
// &Indexer,
|
||||
// &indexes::Vecs,
|
||||
// &Indexes,
|
||||
// &Exit,
|
||||
// ) -> Result<()>,
|
||||
// {
|
||||
// compute(
|
||||
// self.txindex.as_mut().unwrap(),
|
||||
// indexer,
|
||||
// indexes,
|
||||
// starting_indexes,
|
||||
// exit,
|
||||
// )?;
|
||||
|
||||
// let txindex: Option<&StoredVec<TxIndex, T>> = None;
|
||||
// self.compute_rest(indexer, indexes, starting_indexes, exit, txindex)?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
txindex: Option<&impl CollectableVec<TxIndex, T>>,
|
||||
) -> Result<()> {
|
||||
if let Some(txindex) = txindex {
|
||||
self.height.compute(
|
||||
starting_indexes.height,
|
||||
txindex,
|
||||
&indexer.vecs.height_to_first_txindex,
|
||||
&indexes.height_to_txindex_count,
|
||||
exit,
|
||||
)?;
|
||||
} else {
|
||||
let txindex = self.txindex.as_ref().unwrap().as_ref();
|
||||
|
||||
self.height.compute(
|
||||
starting_indexes.height,
|
||||
txindex,
|
||||
&indexer.vecs.height_to_first_txindex,
|
||||
&indexes.height_to_txindex_count,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.compute_after_height(indexes, starting_indexes, exit)
|
||||
}
|
||||
|
||||
fn compute_after_height(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.dateindex.from_aligned(
|
||||
starting_indexes.dateindex,
|
||||
&self.height,
|
||||
&indexes.dateindex_to_first_height,
|
||||
&indexes.dateindex_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.compute_if_necessary(
|
||||
starting_indexes.weekindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute_if_necessary(
|
||||
starting_indexes.monthindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.compute_if_necessary(
|
||||
starting_indexes.quarterindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.semesterindex.compute_if_necessary(
|
||||
starting_indexes.semesterindex,
|
||||
&indexes.semesterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.compute_if_necessary(
|
||||
starting_indexes.yearindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.compute_if_necessary(
|
||||
starting_indexes.decadeindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.from_aligned(
|
||||
starting_indexes.difficultyepoch,
|
||||
&self.height,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
&indexes.difficultyepoch_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.txindex
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| vec![v.as_ref() as &dyn AnyCollectableVec]),
|
||||
self.height.vecs(),
|
||||
self.dateindex.vecs(),
|
||||
self.weekindex.vecs(),
|
||||
self.difficultyepoch.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.semesterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
// self.halvingepoch.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedVecsFromTxindex<Bitcoin> {
|
||||
pub fn compute_rest_from_sats(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
sats: &ComputedVecsFromTxindex<Sats>,
|
||||
txindex: Option<&impl CollectableVec<TxIndex, Bitcoin>>,
|
||||
) -> Result<()> {
|
||||
let txindex_version = if let Some(txindex) = txindex {
|
||||
txindex.version()
|
||||
} else {
|
||||
self.txindex.as_ref().unwrap().as_ref().version()
|
||||
};
|
||||
|
||||
self.height
|
||||
.validate_computed_version_or_reset_file(txindex_version)?;
|
||||
|
||||
let starting_index = self.height.starting_index(starting_indexes.height);
|
||||
|
||||
(starting_index.unwrap_to_usize()..indexer.vecs.height_to_weight.len())
|
||||
.map(Height::from)
|
||||
.try_for_each(|height| -> Result<()> {
|
||||
if let Some(first) = self.height.first.as_mut() {
|
||||
first.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_first()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(average) = self.height.average.as_mut() {
|
||||
average.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_average()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(sum) = self.height.sum.as_mut() {
|
||||
sum.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_sum()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(max) = self.height.max.as_mut() {
|
||||
max.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_max()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_90p) = self.height._90p.as_mut() {
|
||||
_90p.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_90p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_75p) = self.height._75p.as_mut() {
|
||||
_75p.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_75p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(median) = self.height.median.as_mut() {
|
||||
median.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_median()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_25p) = self.height._25p.as_mut() {
|
||||
_25p.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_25p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_10p) = self.height._10p.as_mut() {
|
||||
_10p.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_10p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(min) = self.height.min.as_mut() {
|
||||
min.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_min()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(last) = self.height.last.as_mut() {
|
||||
last.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_last()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(cumulative) = self.height.cumulative.as_mut() {
|
||||
cumulative.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_cumulative()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.height.safe_flush(exit)?;
|
||||
|
||||
self.compute_after_height(indexes, starting_indexes, exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedVecsFromTxindex<Dollars> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn compute_rest_from_bitcoin(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
bitcoin: &ComputedVecsFromTxindex<Bitcoin>,
|
||||
txindex: Option<&impl CollectableVec<TxIndex, Dollars>>,
|
||||
fetched: &fetched::Vecs,
|
||||
) -> Result<()> {
|
||||
let txindex_version = if let Some(txindex) = txindex {
|
||||
txindex.version()
|
||||
} else {
|
||||
self.txindex.as_ref().unwrap().as_ref().version()
|
||||
};
|
||||
|
||||
self.height
|
||||
.validate_computed_version_or_reset_file(txindex_version)?;
|
||||
|
||||
let starting_index = self.height.starting_index(starting_indexes.height);
|
||||
|
||||
let mut close_iter = fetched.chainindexes_to_close.height.into_iter();
|
||||
|
||||
(starting_index.unwrap_to_usize()..indexer.vecs.height_to_weight.len())
|
||||
.map(Height::from)
|
||||
.try_for_each(|height| -> Result<()> {
|
||||
let price = *close_iter.unwrap_get_inner(height);
|
||||
|
||||
if let Some(first) = self.height.first.as_mut() {
|
||||
first.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_first()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(average) = self.height.average.as_mut() {
|
||||
average.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_average()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(sum) = self.height.sum.as_mut() {
|
||||
sum.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_sum()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(max) = self.height.max.as_mut() {
|
||||
max.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_max()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_90p) = self.height._90p.as_mut() {
|
||||
_90p.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_90p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_75p) = self.height._75p.as_mut() {
|
||||
_75p.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_75p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(median) = self.height.median.as_mut() {
|
||||
median.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_median()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_25p) = self.height._25p.as_mut() {
|
||||
_25p.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_25p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_10p) = self.height._10p.as_mut() {
|
||||
_10p.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_10p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(min) = self.height.min.as_mut() {
|
||||
min.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_min()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(last) = self.height.last.as_mut() {
|
||||
last.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_last()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(cumulative) = self.height.cumulative.as_mut() {
|
||||
cumulative.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_cumulative()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.height.safe_flush(exit)?;
|
||||
|
||||
self.compute_after_height(indexes, starting_indexes, exit)
|
||||
}
|
||||
}
|
||||
27
crates/brk_computer/src/grouped/mod.rs
Normal file
27
crates/brk_computer/src/grouped/mod.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
mod builder_computed;
|
||||
mod builder_eager;
|
||||
mod from_dateindex;
|
||||
mod from_height;
|
||||
mod from_height_strict;
|
||||
mod from_txindex;
|
||||
mod ratio_from_dateindex;
|
||||
mod source;
|
||||
mod r#type;
|
||||
mod value_from_dateindex;
|
||||
mod value_from_height;
|
||||
mod value_from_txindex;
|
||||
mod value_height;
|
||||
|
||||
pub use builder_computed::*;
|
||||
pub use builder_eager::*;
|
||||
pub use from_dateindex::*;
|
||||
pub use from_height::*;
|
||||
pub use from_height_strict::*;
|
||||
pub use from_txindex::*;
|
||||
pub use ratio_from_dateindex::*;
|
||||
pub use source::*;
|
||||
use r#type::*;
|
||||
pub use value_from_dateindex::*;
|
||||
pub use value_from_height::*;
|
||||
pub use value_from_txindex::*;
|
||||
pub use value_height::*;
|
||||
1676
crates/brk_computer/src/grouped/ratio_from_dateindex.rs
Normal file
1676
crates/brk_computer/src/grouped/ratio_from_dateindex.rs
Normal file
File diff suppressed because it is too large
Load Diff
51
crates/brk_computer/src/grouped/source.rs
Normal file
51
crates/brk_computer/src/grouped/source.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use brk_vec::BoxedAnyIterableVec;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Source<I, T> {
|
||||
Compute,
|
||||
None,
|
||||
Vec(BoxedAnyIterableVec<I, T>),
|
||||
}
|
||||
|
||||
impl<I, T> Source<I, T> {
|
||||
pub fn is_compute(&self) -> bool {
|
||||
matches!(self, Self::Compute)
|
||||
}
|
||||
|
||||
pub fn is_none(&self) -> bool {
|
||||
matches!(self, Self::None)
|
||||
}
|
||||
|
||||
pub fn is_vec(&self) -> bool {
|
||||
matches!(self, Self::Vec(_))
|
||||
}
|
||||
|
||||
pub fn vec(self) -> Option<BoxedAnyIterableVec<I, T>> {
|
||||
match self {
|
||||
Self::Vec(v) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> From<bool> for Source<I, T> {
|
||||
fn from(value: bool) -> Self {
|
||||
if value { Self::Compute } else { Self::None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> From<BoxedAnyIterableVec<I, T>> for Source<I, T> {
|
||||
fn from(value: BoxedAnyIterableVec<I, T>) -> Self {
|
||||
Self::Vec(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> From<Option<BoxedAnyIterableVec<I, T>>> for Source<I, T> {
|
||||
fn from(value: Option<BoxedAnyIterableVec<I, T>>) -> Self {
|
||||
if let Some(v) = value {
|
||||
Self::Vec(v)
|
||||
} else {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
}
|
||||
14
crates/brk_computer/src/grouped/type.rs
Normal file
14
crates/brk_computer/src/grouped/type.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use std::ops::{Add, AddAssign, Div};
|
||||
|
||||
use brk_vec::StoredType;
|
||||
|
||||
pub trait ComputedType
|
||||
where
|
||||
Self:
|
||||
StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + AddAssign + Ord,
|
||||
{
|
||||
}
|
||||
impl<T> ComputedType for T where
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + AddAssign + Ord
|
||||
{
|
||||
}
|
||||
185
crates/brk_computer/src/grouped/value_from_dateindex.rs
Normal file
185
crates/brk_computer/src/grouped/value_from_dateindex.rs
Normal file
@@ -0,0 +1,185 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, DateIndex, Dollars, Result, Sats, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, Computation, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::{Indexes, fetched, grouped::ComputedVecsFromDateIndex, indexes};
|
||||
|
||||
use super::{Source, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromDateIndex {
|
||||
pub sats: ComputedVecsFromDateIndex<Sats>,
|
||||
pub bitcoin: ComputedVecsFromDateIndex<Bitcoin>,
|
||||
pub dollars: Option<ComputedVecsFromDateIndex<Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedValueVecsFromDateIndex {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
source: Source<DateIndex, Sats>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
computation: Computation,
|
||||
options: VecBuilderOptions,
|
||||
compute_dollars: bool,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
name,
|
||||
source,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?,
|
||||
bitcoin: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<DateIndex, Sats>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.dateindex.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let dateindex: Option<&StoredVec<DateIndex, Sats>> = None;
|
||||
self.compute_rest(indexer, indexes, fetched, starting_indexes, exit, dateindex)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
dateindex: Option<&impl CollectableVec<DateIndex, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(dateindex) = dateindex {
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, Some(dateindex))?;
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(starting_indexes.dateindex, dateindex, exit)
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
let dateindex: Option<&StoredVec<DateIndex, Sats>> = None;
|
||||
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, dateindex)?;
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(
|
||||
starting_indexes.dateindex,
|
||||
self.sats.dateindex.as_ref().unwrap(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
let dateindex_to_bitcoin = self.bitcoin.dateindex.as_ref().unwrap();
|
||||
let dateindex_to_close = fetched
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.timeindexes_to_close
|
||||
.dateindex
|
||||
.as_ref()
|
||||
.unwrap();
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
dollars.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_bitcoin(
|
||||
starting_indexes.dateindex,
|
||||
dateindex_to_bitcoin,
|
||||
dateindex_to_close,
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.sats.vecs(),
|
||||
self.bitcoin.vecs(),
|
||||
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
179
crates/brk_computer/src/grouped/value_from_height.rs
Normal file
179
crates/brk_computer/src/grouped/value_from_height.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, Dollars, Height, Result, Sats, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, Computation, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::{Indexes, fetched, grouped::Source, indexes};
|
||||
|
||||
use super::{ComputedVecsFromHeight, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromHeight {
|
||||
pub sats: ComputedVecsFromHeight<Sats>,
|
||||
pub bitcoin: ComputedVecsFromHeight<Bitcoin>,
|
||||
pub dollars: Option<ComputedVecsFromHeight<Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedValueVecsFromHeight {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
source: Source<Height, Sats>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
computation: Computation,
|
||||
options: VecBuilderOptions,
|
||||
compute_dollars: bool,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
name,
|
||||
source,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?,
|
||||
bitcoin: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<Height, Sats>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.height.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let height: Option<&StoredVec<Height, Sats>> = None;
|
||||
self.compute_rest(indexer, indexes, fetched, starting_indexes, exit, height)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&impl CollectableVec<Height, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height {
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, Some(height))?;
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(starting_indexes.height, height, exit)
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
let height: Option<&StoredVec<Height, Sats>> = None;
|
||||
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, height)?;
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(
|
||||
starting_indexes.height,
|
||||
self.sats.height.as_ref().unwrap(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
let height_to_bitcoin = self.bitcoin.height.as_ref().unwrap();
|
||||
let height_to_close = &fetched.as_ref().unwrap().chainindexes_to_close.height;
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
dollars.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_bitcoin(
|
||||
starting_indexes.height,
|
||||
height_to_bitcoin,
|
||||
height_to_close,
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.sats.vecs(),
|
||||
self.bitcoin.vecs(),
|
||||
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
247
crates/brk_computer/src/grouped/value_from_txindex.rs
Normal file
247
crates/brk_computer/src/grouped/value_from_txindex.rs
Normal file
@@ -0,0 +1,247 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, Close, Dollars, Height, Sats, TxIndex, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, CloneableAnyIterableVec, CollectableVec, Computation, ComputedVecFrom3,
|
||||
Format, LazyVecFrom1, StoredIndex, StoredVec,
|
||||
};
|
||||
|
||||
use crate::{Indexes, fetched, grouped::Source, indexes};
|
||||
|
||||
use super::{ComputedVecsFromTxindex, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromTxindex {
|
||||
pub sats: ComputedVecsFromTxindex<Sats>,
|
||||
pub bitcoin_txindex: LazyVecFrom1<TxIndex, Bitcoin, TxIndex, Sats>,
|
||||
pub bitcoin: ComputedVecsFromTxindex<Bitcoin>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub dollars_txindex: Option<
|
||||
ComputedVecFrom3<
|
||||
TxIndex,
|
||||
Dollars,
|
||||
TxIndex,
|
||||
Bitcoin,
|
||||
TxIndex,
|
||||
Height,
|
||||
Height,
|
||||
Close<Dollars>,
|
||||
>,
|
||||
>,
|
||||
pub dollars: Option<ComputedVecsFromTxindex<Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedValueVecsFromTxindex {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
indexes: &indexes::Vecs,
|
||||
source: Source<TxIndex, Sats>,
|
||||
version: Version,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let compute_dollars = fetched.is_some();
|
||||
|
||||
let name_in_btc = format!("{name}_in_btc");
|
||||
let name_in_usd = format!("{name}_in_usd");
|
||||
|
||||
let sats = ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
name,
|
||||
source.clone(),
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let source_vec = source.vec();
|
||||
|
||||
let bitcoin_txindex = LazyVecFrom1::init(
|
||||
&name_in_btc,
|
||||
version + VERSION,
|
||||
source_vec.map_or_else(|| sats.txindex.as_ref().unwrap().boxed_clone(), |s| s),
|
||||
|txindex: TxIndex, iter| {
|
||||
iter.next_at(txindex.unwrap_to_usize()).map(|(_, value)| {
|
||||
let sats = value.into_owned();
|
||||
Bitcoin::from(sats)
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let bitcoin = ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
&name_in_btc,
|
||||
Source::None,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let dollars_txindex = fetched.map(|fetched| {
|
||||
ComputedVecFrom3::forced_import_or_init_from_3(
|
||||
computation,
|
||||
path,
|
||||
&name_in_usd,
|
||||
version + VERSION,
|
||||
format,
|
||||
bitcoin_txindex.boxed_clone(),
|
||||
indexes.txindex_to_height.boxed_clone(),
|
||||
fetched.chainindexes_to_close.height.boxed_clone(),
|
||||
|txindex: TxIndex,
|
||||
txindex_to_btc_iter,
|
||||
txindex_to_height_iter,
|
||||
height_to_close_iter| {
|
||||
let txindex = txindex.unwrap_to_usize();
|
||||
txindex_to_btc_iter.next_at(txindex).and_then(|(_, value)| {
|
||||
let btc = value.into_owned();
|
||||
txindex_to_height_iter
|
||||
.next_at(txindex)
|
||||
.and_then(|(_, value)| {
|
||||
let height = value.into_owned();
|
||||
height_to_close_iter
|
||||
.next_at(height.unwrap_to_usize())
|
||||
.map(|(_, close)| *close.into_owned() * btc)
|
||||
})
|
||||
})
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
sats,
|
||||
bitcoin_txindex,
|
||||
bitcoin,
|
||||
dollars_txindex,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
&name_in_usd,
|
||||
Source::None,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn compute_all<F>(
|
||||
// &mut self,
|
||||
// indexer: &Indexer,
|
||||
// indexes: &indexes::Vecs,
|
||||
// fetched: Option<&marketprice::Vecs>,
|
||||
// starting_indexes: &Indexes,
|
||||
// exit: &Exit,
|
||||
// mut compute: F,
|
||||
// ) -> color_eyre::Result<()>
|
||||
// where
|
||||
// F: FnMut(
|
||||
// &mut EagerVec<TxIndex, Sats>,
|
||||
// &Indexer,
|
||||
// &indexes::Vecs,
|
||||
// &Indexes,
|
||||
// &Exit,
|
||||
// ) -> Result<()>,
|
||||
// {
|
||||
// compute(
|
||||
// self.sats.txindex.as_mut().unwrap(),
|
||||
// indexer,
|
||||
// indexes,
|
||||
// starting_indexes,
|
||||
// exit,
|
||||
// )?;
|
||||
|
||||
// let txindex: Option<&StoredVec<TxIndex, Sats>> = None;
|
||||
// self.compute_rest(
|
||||
// indexer,
|
||||
// indexes,
|
||||
// fetched,
|
||||
// starting_indexes,
|
||||
// exit,
|
||||
// txindex,
|
||||
// )?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
txindex: Option<&impl CollectableVec<TxIndex, Sats>>,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(txindex) = txindex {
|
||||
self.sats
|
||||
.compute_rest(indexer, indexes, starting_indexes, exit, Some(txindex))?;
|
||||
} else {
|
||||
let txindex: Option<&StoredVec<TxIndex, Sats>> = None;
|
||||
self.sats
|
||||
.compute_rest(indexer, indexes, starting_indexes, exit, txindex)?;
|
||||
}
|
||||
|
||||
self.bitcoin.compute_rest_from_sats(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.sats,
|
||||
Some(&self.bitcoin_txindex),
|
||||
)?;
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
let dollars_txindex = self.dollars_txindex.as_mut().unwrap();
|
||||
|
||||
dollars_txindex.compute_if_necessary(
|
||||
starting_indexes.txindex,
|
||||
&indexer.vecs.txindex_to_txid,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
dollars.compute_rest_from_bitcoin(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.bitcoin,
|
||||
Some(dollars_txindex),
|
||||
fetched.as_ref().unwrap(),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.sats.vecs(),
|
||||
vec![&self.bitcoin_txindex as &dyn AnyCollectableVec],
|
||||
self.bitcoin.vecs(),
|
||||
self.dollars_txindex
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| vec![v as &dyn AnyCollectableVec]),
|
||||
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
126
crates/brk_computer/src/grouped/value_height.rs
Normal file
126
crates/brk_computer/src/grouped/value_height.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, Dollars, Height, Result, Sats, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::{Indexes, fetched, grouped::Source, indexes};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedHeightValueVecs {
|
||||
pub sats: Option<EagerVec<Height, Sats>>,
|
||||
pub bitcoin: EagerVec<Height, Bitcoin>,
|
||||
pub dollars: Option<EagerVec<Height, Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedHeightValueVecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
source: Source<Height, Sats>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: source.is_compute().then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)
|
||||
.unwrap()
|
||||
}),
|
||||
bitcoin: EagerVec::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<Height, Sats>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let height: Option<&StoredVec<Height, Sats>> = None;
|
||||
self.compute_rest(fetched, starting_indexes, exit, height)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&impl CollectableVec<Height, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height {
|
||||
self.bitcoin
|
||||
.compute_from_sats(starting_indexes.height, height, exit)?;
|
||||
} else {
|
||||
self.bitcoin.compute_from_sats(
|
||||
starting_indexes.height,
|
||||
self.sats.as_ref().unwrap(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
let height_to_bitcoin = &self.bitcoin;
|
||||
let height_to_close = &fetched.as_ref().unwrap().chainindexes_to_close.height;
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
dollars.compute_from_bitcoin(
|
||||
starting_indexes.height,
|
||||
height_to_bitcoin,
|
||||
height_to_close,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
vec![&self.bitcoin as &dyn AnyCollectableVec],
|
||||
self.sats.as_ref().map_or(vec![], |v| vec![v]),
|
||||
self.dollars.as_ref().map_or(vec![], |v| vec![v]),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user