use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, StoredF32, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{
DeltaChange, DeltaRate, LazyDeltaVec, LazyVecFrom1, ReadOnlyClone, ReadableCloneableVec,
VecValue,
};
use crate::{
indexes,
internal::{
AmountType, BpsType, DerivedResolutions, FiatType, LazyPerBlock, NumericValue, Percent,
Resolutions, WindowStartVec, Windows,
},
};
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct LazyDeltaFromHeight<S, T, Op: 'static>
where
S: VecValue,
T: NumericValue + JsonSchema,
{
pub height: LazyDeltaVec<Height, S, T, Op>,
#[traversable(flatten)]
pub resolutions: Box<Resolutions<T>>,
}
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyDeltaPercentFromHeight<S, B>(
pub Percent<LazyDeltaFromHeight<S, B, DeltaRate>, LazyPerBlock<StoredF32, B>>,
)
where
S: VecValue,
B: BpsType;
#[derive(Clone, Traversable)]
pub struct LazyRollingDeltasFromHeight<S, C, B>
where
S: VecValue,
C: NumericValue + JsonSchema,
B: BpsType,
{
pub absolute: Windows<LazyDeltaFromHeight<S, C, DeltaChange>>,
pub rate: Windows<LazyDeltaPercentFromHeight<S, B>>,
}
impl<S, C, B> LazyRollingDeltasFromHeight<S, C, B>
where
S: VecValue + Into<f64>,
C: NumericValue + JsonSchema + From<f64>,
B: BpsType + From<f64>,
{
pub fn new(
name: &str,
version: Version,
source: &(impl ReadableCloneableVec<Height, S> + 'static),
cached_starts: &Windows<&WindowStartVec>,
indexes: &indexes::Vecs,
) -> Self {
let src = source.read_only_boxed_clone();
let make_slot = |suffix: &str, cached_start: &&WindowStartVec| {
let full_name = format!("{name}_{suffix}");
let cached = cached_start.read_only_clone();
let starts_version = cached.version();
let change_vec = LazyDeltaVec::<Height, S, C, DeltaChange>::new(
&full_name,
version,
src.clone(),
starts_version,
{
let cached = cached.clone();
move || cached.cached()
},
);
let change_resolutions =
Resolutions::forced_import(&full_name, change_vec.clone(), version, indexes);
let absolute = LazyDeltaFromHeight {
height: change_vec,
resolutions: Box::new(change_resolutions),
};
let rate_bps_name = format!("{full_name}_rate_bps");
let rate_vec = LazyDeltaVec::<Height, S, B, DeltaRate>::new(
&rate_bps_name,
version,
src.clone(),
starts_version,
move || cached.cached(),
);
let rate_resolutions =
Resolutions::forced_import(&rate_bps_name, rate_vec.clone(), version, indexes);
let bps = LazyDeltaFromHeight {
height: rate_vec,
resolutions: Box::new(rate_resolutions),
};
let rate_ratio_name = format!("{full_name}_rate_ratio");
let ratio = LazyPerBlock {
height: LazyVecFrom1::transformed::<B::ToRatio>(
&rate_ratio_name,
version,
bps.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToRatio>(
&rate_ratio_name,
version,
&bps.resolutions,
)),
};
let rate_name = format!("{full_name}_rate");
let percent = LazyPerBlock {
height: LazyVecFrom1::transformed::<B::ToPercent>(
&rate_name,
version,
bps.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToPercent>(
&rate_name,
version,
&bps.resolutions,
)),
};
let rate = LazyDeltaPercentFromHeight(Percent {
bps,
ratio,
percent,
});
(absolute, rate)
};
let (absolute, rate) = cached_starts.map_with_suffix(make_slot).unzip();
Self { absolute, rate }
}
}
#[derive(Clone, Traversable)]
pub struct LazyDeltaAmountFromHeight<S, C>
where
S: VecValue,
C: AmountType,
{
pub btc: LazyPerBlock<Bitcoin, C>,
pub sats: LazyDeltaFromHeight<S, C, DeltaChange>,
}
#[derive(Clone, Traversable)]
pub struct LazyRollingDeltasAmountFromHeight<S, C, B>
where
S: VecValue,
C: AmountType,
B: BpsType,
{
pub absolute: Windows<LazyDeltaAmountFromHeight<S, C>>,
pub rate: Windows<LazyDeltaPercentFromHeight<S, B>>,
}
impl<S, C, B> LazyRollingDeltasAmountFromHeight<S, C, B>
where
S: VecValue + Into<f64>,
C: AmountType + From<f64>,
B: BpsType + From<f64>,
{
pub fn new(
name: &str,
version: Version,
source: &(impl ReadableCloneableVec<Height, S> + 'static),
cached_starts: &Windows<&WindowStartVec>,
indexes: &indexes::Vecs,
) -> Self {
let src = source.read_only_boxed_clone();
let make_slot = |suffix: &str, cached_start: &&WindowStartVec| {
let full_name = format!("{name}_{suffix}");
let cached = cached_start.read_only_clone();
let starts_version = cached.version();
let sats_name = format!("{full_name}_sats");
let change_vec = LazyDeltaVec::<Height, S, C, DeltaChange>::new(
&sats_name,
version,
src.clone(),
starts_version,
{
let cached = cached.clone();
move || cached.cached()
},
);
let change_resolutions =
Resolutions::forced_import(&sats_name, change_vec.clone(), version, indexes);
let sats = LazyDeltaFromHeight {
height: change_vec,
resolutions: Box::new(change_resolutions),
};
let btc = LazyPerBlock {
height: LazyVecFrom1::transformed::<C::ToBitcoin>(
&full_name,
version,
sats.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<C::ToBitcoin>(
&full_name,
version,
&sats.resolutions,
)),
};
let absolute = LazyDeltaAmountFromHeight { btc, sats };
let rate_bps_name = format!("{full_name}_rate_bps");
let rate_vec = LazyDeltaVec::<Height, S, B, DeltaRate>::new(
&rate_bps_name,
version,
src.clone(),
starts_version,
move || cached.cached(),
);
let rate_resolutions =
Resolutions::forced_import(&rate_bps_name, rate_vec.clone(), version, indexes);
let bps = LazyDeltaFromHeight {
height: rate_vec,
resolutions: Box::new(rate_resolutions),
};
let rate_ratio_name = format!("{full_name}_rate_ratio");
let ratio = LazyPerBlock {
height: LazyVecFrom1::transformed::<B::ToRatio>(
&rate_ratio_name,
version,
bps.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToRatio>(
&rate_ratio_name,
version,
&bps.resolutions,
)),
};
let rate_name = format!("{full_name}_rate");
let percent = LazyPerBlock {
height: LazyVecFrom1::transformed::<B::ToPercent>(
&rate_name,
version,
bps.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToPercent>(
&rate_name,
version,
&bps.resolutions,
)),
};
let rate = LazyDeltaPercentFromHeight(Percent {
bps,
ratio,
percent,
});
(absolute, rate)
};
let (absolute, rate) = cached_starts.map_with_suffix(make_slot).unzip();
Self { absolute, rate }
}
}
#[derive(Clone, Traversable)]
pub struct LazyDeltaFiatFromHeight<S, C>
where
S: VecValue,
C: FiatType,
{
pub usd: LazyPerBlock<Dollars, C>,
pub cents: LazyDeltaFromHeight<S, C, DeltaChange>,
}
#[derive(Clone, Traversable)]
pub struct LazyRollingDeltasFiatFromHeight<S, C, B>
where
S: VecValue,
C: FiatType,
B: BpsType,
{
pub absolute: Windows<LazyDeltaFiatFromHeight<S, C>>,
pub rate: Windows<LazyDeltaPercentFromHeight<S, B>>,
}
impl<S, C, B> LazyRollingDeltasFiatFromHeight<S, C, B>
where
S: VecValue + Into<f64>,
C: FiatType + From<f64>,
B: BpsType + From<f64>,
{
pub fn new(
name: &str,
version: Version,
source: &(impl ReadableCloneableVec<Height, S> + 'static),
cached_starts: &Windows<&WindowStartVec>,
indexes: &indexes::Vecs,
) -> Self {
let src = source.read_only_boxed_clone();
let make_slot = |suffix: &str, cached_start: &&WindowStartVec| {
let full_name = format!("{name}_{suffix}");
let cached = cached_start.read_only_clone();
let starts_version = cached.version();
let cents_name = format!("{full_name}_cents");
let change_vec = LazyDeltaVec::<Height, S, C, DeltaChange>::new(
¢s_name,
version,
src.clone(),
starts_version,
{
let cached = cached.clone();
move || cached.cached()
},
);
let change_resolutions =
Resolutions::forced_import(¢s_name, change_vec.clone(), version, indexes);
let cents = LazyDeltaFromHeight {
height: change_vec,
resolutions: Box::new(change_resolutions),
};
let usd = LazyPerBlock {
height: LazyVecFrom1::transformed::<C::ToDollars>(
&full_name,
version,
cents.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<C::ToDollars>(
&full_name,
version,
¢s.resolutions,
)),
};
let absolute = LazyDeltaFiatFromHeight { usd, cents };
let rate_bps_name = format!("{full_name}_rate_bps");
let rate_vec = LazyDeltaVec::<Height, S, B, DeltaRate>::new(
&rate_bps_name,
version,
src.clone(),
starts_version,
move || cached.cached(),
);
let rate_resolutions =
Resolutions::forced_import(&rate_bps_name, rate_vec.clone(), version, indexes);
let bps = LazyDeltaFromHeight {
height: rate_vec,
resolutions: Box::new(rate_resolutions),
};
let rate_ratio_name = format!("{full_name}_rate_ratio");
let ratio = LazyPerBlock {
height: LazyVecFrom1::transformed::<B::ToRatio>(
&rate_ratio_name,
version,
bps.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToRatio>(
&rate_ratio_name,
version,
&bps.resolutions,
)),
};
let rate_name = format!("{full_name}_rate");
let percent = LazyPerBlock {
height: LazyVecFrom1::transformed::<B::ToPercent>(
&rate_name,
version,
bps.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToPercent>(
&rate_name,
version,
&bps.resolutions,
)),
};
let rate = LazyDeltaPercentFromHeight(Percent {
bps,
ratio,
percent,
});
(absolute, rate)
};
let (absolute, rate) = cached_starts.map_with_suffix(make_slot).unzip();
Self { absolute, rate }
}
}