global: snapshot

This commit is contained in:
nym21
2026-01-04 11:51:22 +01:00
parent 3cae817915
commit 13ab7d39d7
26 changed files with 1696 additions and 1467 deletions

View File

@@ -1,66 +1,71 @@
use std::ops::Range;
use brk_types::Age;
use brk_traversable::Traversable;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::Serialize;
use super::{CohortName, Filter, TimeFilter};
// Age boundary constants in days
pub const DAYS_1D: usize = 1;
pub const DAYS_1W: usize = 7;
pub const DAYS_1M: usize = 30;
pub const DAYS_2M: usize = 2 * 30;
pub const DAYS_3M: usize = 3 * 30;
pub const DAYS_4M: usize = 4 * 30;
pub const DAYS_5M: usize = 5 * 30;
pub const DAYS_6M: usize = 6 * 30;
pub const DAYS_1Y: usize = 365;
pub const DAYS_2Y: usize = 2 * 365;
pub const DAYS_3Y: usize = 3 * 365;
pub const DAYS_4Y: usize = 4 * 365;
pub const DAYS_5Y: usize = 5 * 365;
pub const DAYS_6Y: usize = 6 * 365;
pub const DAYS_7Y: usize = 7 * 365;
pub const DAYS_8Y: usize = 8 * 365;
pub const DAYS_10Y: usize = 10 * 365;
pub const DAYS_12Y: usize = 12 * 365;
pub const DAYS_15Y: usize = 15 * 365;
// Age boundary constants in hours
pub const HOURS_1H: usize = 1;
pub const HOURS_1D: usize = 24;
pub const HOURS_1W: usize = 24 * 7;
pub const HOURS_1M: usize = 24 * 30;
pub const HOURS_2M: usize = 24 * 2 * 30;
pub const HOURS_3M: usize = 24 * 3 * 30;
pub const HOURS_4M: usize = 24 * 4 * 30;
pub const HOURS_5M: usize = 24 * 5 * 30; // STH/LTH threshold
pub const HOURS_6M: usize = 24 * 6 * 30;
pub const HOURS_1Y: usize = 24 * 365;
pub const HOURS_2Y: usize = 24 * 2 * 365;
pub const HOURS_3Y: usize = 24 * 3 * 365;
pub const HOURS_4Y: usize = 24 * 4 * 365;
pub const HOURS_5Y: usize = 24 * 5 * 365;
pub const HOURS_6Y: usize = 24 * 6 * 365;
pub const HOURS_7Y: usize = 24 * 7 * 365;
pub const HOURS_8Y: usize = 24 * 8 * 365;
pub const HOURS_10Y: usize = 24 * 10 * 365;
pub const HOURS_12Y: usize = 24 * 12 * 365;
pub const HOURS_15Y: usize = 24 * 15 * 365;
/// Age boundaries in days. Defines the cohort ranges:
/// [0, B[0]), [B[0], B[1]), [B[1], B[2]), ..., [B[n-1], ∞)
pub const AGE_BOUNDARIES: [usize; 19] = [
DAYS_1D, DAYS_1W, DAYS_1M, DAYS_2M, DAYS_3M, DAYS_4M, DAYS_5M, DAYS_6M, DAYS_1Y, DAYS_2Y,
DAYS_3Y, DAYS_4Y, DAYS_5Y, DAYS_6Y, DAYS_7Y, DAYS_8Y, DAYS_10Y, DAYS_12Y, DAYS_15Y,
/// Age boundaries in hours. Defines the cohort ranges:
/// [0, 1h), [1h, 1d), [1d, 1w), [1w, 1m), ..., [15y, ∞)
pub const AGE_BOUNDARIES: [usize; 20] = [
HOURS_1H, HOURS_1D, HOURS_1W, HOURS_1M, HOURS_2M, HOURS_3M, HOURS_4M,
HOURS_5M, HOURS_6M, HOURS_1Y, HOURS_2Y, HOURS_3Y, HOURS_4Y, HOURS_5Y,
HOURS_6Y, HOURS_7Y, HOURS_8Y, HOURS_10Y, HOURS_12Y, HOURS_15Y,
];
/// Age range bounds (end = usize::MAX means unbounded)
pub const AGE_RANGE_BOUNDS: ByAgeRange<Range<usize>> = ByAgeRange {
up_to_1d: 0..DAYS_1D,
_1d_to_1w: DAYS_1D..DAYS_1W,
_1w_to_1m: DAYS_1W..DAYS_1M,
_1m_to_2m: DAYS_1M..DAYS_2M,
_2m_to_3m: DAYS_2M..DAYS_3M,
_3m_to_4m: DAYS_3M..DAYS_4M,
_4m_to_5m: DAYS_4M..DAYS_5M,
_5m_to_6m: DAYS_5M..DAYS_6M,
_6m_to_1y: DAYS_6M..DAYS_1Y,
_1y_to_2y: DAYS_1Y..DAYS_2Y,
_2y_to_3y: DAYS_2Y..DAYS_3Y,
_3y_to_4y: DAYS_3Y..DAYS_4Y,
_4y_to_5y: DAYS_4Y..DAYS_5Y,
_5y_to_6y: DAYS_5Y..DAYS_6Y,
_6y_to_7y: DAYS_6Y..DAYS_7Y,
_7y_to_8y: DAYS_7Y..DAYS_8Y,
_8y_to_10y: DAYS_8Y..DAYS_10Y,
_10y_to_12y: DAYS_10Y..DAYS_12Y,
_12y_to_15y: DAYS_12Y..DAYS_15Y,
from_15y: DAYS_15Y..usize::MAX,
up_to_1h: 0..HOURS_1H,
_1h_to_1d: HOURS_1H..HOURS_1D,
_1d_to_1w: HOURS_1D..HOURS_1W,
_1w_to_1m: HOURS_1W..HOURS_1M,
_1m_to_2m: HOURS_1M..HOURS_2M,
_2m_to_3m: HOURS_2M..HOURS_3M,
_3m_to_4m: HOURS_3M..HOURS_4M,
_4m_to_5m: HOURS_4M..HOURS_5M,
_5m_to_6m: HOURS_5M..HOURS_6M,
_6m_to_1y: HOURS_6M..HOURS_1Y,
_1y_to_2y: HOURS_1Y..HOURS_2Y,
_2y_to_3y: HOURS_2Y..HOURS_3Y,
_3y_to_4y: HOURS_3Y..HOURS_4Y,
_4y_to_5y: HOURS_4Y..HOURS_5Y,
_5y_to_6y: HOURS_5Y..HOURS_6Y,
_6y_to_7y: HOURS_6Y..HOURS_7Y,
_7y_to_8y: HOURS_7Y..HOURS_8Y,
_8y_to_10y: HOURS_8Y..HOURS_10Y,
_10y_to_12y: HOURS_10Y..HOURS_12Y,
_12y_to_15y: HOURS_12Y..HOURS_15Y,
from_15y: HOURS_15Y..usize::MAX,
};
/// Age range filters
pub const AGE_RANGE_FILTERS: ByAgeRange<Filter> = ByAgeRange {
up_to_1d: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS.up_to_1d)),
up_to_1h: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS.up_to_1h)),
_1h_to_1d: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS._1h_to_1d)),
_1d_to_1w: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS._1d_to_1w)),
_1w_to_1m: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS._1w_to_1m)),
_1m_to_2m: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS._1m_to_2m)),
@@ -84,7 +89,8 @@ pub const AGE_RANGE_FILTERS: ByAgeRange<Filter> = ByAgeRange {
/// Age range names
pub const AGE_RANGE_NAMES: ByAgeRange<CohortName> = ByAgeRange {
up_to_1d: CohortName::new("up_to_1d_old", "<1d", "Up to 1 Day Old"),
up_to_1h: CohortName::new("up_to_1h_old", "<1h", "Up to 1 Hour Old"),
_1h_to_1d: CohortName::new("at_least_1h_up_to_1d_old", "1h-1d", "1 Hour to 1 Day Old"),
_1d_to_1w: CohortName::new("at_least_1d_up_to_1w_old", "1d-1w", "1 Day to 1 Week Old"),
_1w_to_1m: CohortName::new("at_least_1w_up_to_1m_old", "1w-1m", "1 Week to 1 Month Old"),
_1m_to_2m: CohortName::new("at_least_1m_up_to_2m_old", "1m-2m", "1 to 2 Months Old"),
@@ -114,7 +120,8 @@ impl ByAgeRange<CohortName> {
#[derive(Default, Clone, Traversable, Serialize)]
pub struct ByAgeRange<T> {
pub up_to_1d: T,
pub up_to_1h: T,
pub _1h_to_1d: T,
pub _1d_to_1w: T,
pub _1w_to_1m: T,
pub _1m_to_2m: T,
@@ -137,33 +144,62 @@ pub struct ByAgeRange<T> {
}
impl<T> ByAgeRange<T> {
/// Get mutable reference by days old. O(1).
/// Get mutable reference by Age. O(1).
#[inline]
pub fn get_mut_by_days_old(&mut self, days_old: usize) -> &mut T {
match days_old {
0..DAYS_1D => &mut self.up_to_1d,
DAYS_1D..DAYS_1W => &mut self._1d_to_1w,
DAYS_1W..DAYS_1M => &mut self._1w_to_1m,
DAYS_1M..DAYS_2M => &mut self._1m_to_2m,
DAYS_2M..DAYS_3M => &mut self._2m_to_3m,
DAYS_3M..DAYS_4M => &mut self._3m_to_4m,
DAYS_4M..DAYS_5M => &mut self._4m_to_5m,
DAYS_5M..DAYS_6M => &mut self._5m_to_6m,
DAYS_6M..DAYS_1Y => &mut self._6m_to_1y,
DAYS_1Y..DAYS_2Y => &mut self._1y_to_2y,
DAYS_2Y..DAYS_3Y => &mut self._2y_to_3y,
DAYS_3Y..DAYS_4Y => &mut self._3y_to_4y,
DAYS_4Y..DAYS_5Y => &mut self._4y_to_5y,
DAYS_5Y..DAYS_6Y => &mut self._5y_to_6y,
DAYS_6Y..DAYS_7Y => &mut self._6y_to_7y,
DAYS_7Y..DAYS_8Y => &mut self._7y_to_8y,
DAYS_8Y..DAYS_10Y => &mut self._8y_to_10y,
DAYS_10Y..DAYS_12Y => &mut self._10y_to_12y,
DAYS_12Y..DAYS_15Y => &mut self._12y_to_15y,
pub fn get_mut(&mut self, age: Age) -> &mut T {
match age.hours() {
0..HOURS_1H => &mut self.up_to_1h,
HOURS_1H..HOURS_1D => &mut self._1h_to_1d,
HOURS_1D..HOURS_1W => &mut self._1d_to_1w,
HOURS_1W..HOURS_1M => &mut self._1w_to_1m,
HOURS_1M..HOURS_2M => &mut self._1m_to_2m,
HOURS_2M..HOURS_3M => &mut self._2m_to_3m,
HOURS_3M..HOURS_4M => &mut self._3m_to_4m,
HOURS_4M..HOURS_5M => &mut self._4m_to_5m,
HOURS_5M..HOURS_6M => &mut self._5m_to_6m,
HOURS_6M..HOURS_1Y => &mut self._6m_to_1y,
HOURS_1Y..HOURS_2Y => &mut self._1y_to_2y,
HOURS_2Y..HOURS_3Y => &mut self._2y_to_3y,
HOURS_3Y..HOURS_4Y => &mut self._3y_to_4y,
HOURS_4Y..HOURS_5Y => &mut self._4y_to_5y,
HOURS_5Y..HOURS_6Y => &mut self._5y_to_6y,
HOURS_6Y..HOURS_7Y => &mut self._6y_to_7y,
HOURS_7Y..HOURS_8Y => &mut self._7y_to_8y,
HOURS_8Y..HOURS_10Y => &mut self._8y_to_10y,
HOURS_10Y..HOURS_12Y => &mut self._10y_to_12y,
HOURS_12Y..HOURS_15Y => &mut self._12y_to_15y,
_ => &mut self.from_15y,
}
}
/// Get reference by Age. O(1).
#[inline]
pub fn get(&self, age: Age) -> &T {
match age.hours() {
0..HOURS_1H => &self.up_to_1h,
HOURS_1H..HOURS_1D => &self._1h_to_1d,
HOURS_1D..HOURS_1W => &self._1d_to_1w,
HOURS_1W..HOURS_1M => &self._1w_to_1m,
HOURS_1M..HOURS_2M => &self._1m_to_2m,
HOURS_2M..HOURS_3M => &self._2m_to_3m,
HOURS_3M..HOURS_4M => &self._3m_to_4m,
HOURS_4M..HOURS_5M => &self._4m_to_5m,
HOURS_5M..HOURS_6M => &self._5m_to_6m,
HOURS_6M..HOURS_1Y => &self._6m_to_1y,
HOURS_1Y..HOURS_2Y => &self._1y_to_2y,
HOURS_2Y..HOURS_3Y => &self._2y_to_3y,
HOURS_3Y..HOURS_4Y => &self._3y_to_4y,
HOURS_4Y..HOURS_5Y => &self._4y_to_5y,
HOURS_5Y..HOURS_6Y => &self._5y_to_6y,
HOURS_6Y..HOURS_7Y => &self._6y_to_7y,
HOURS_7Y..HOURS_8Y => &self._7y_to_8y,
HOURS_8Y..HOURS_10Y => &self._8y_to_10y,
HOURS_10Y..HOURS_12Y => &self._10y_to_12y,
HOURS_12Y..HOURS_15Y => &self._12y_to_15y,
_ => &self.from_15y,
}
}
pub fn new<F>(mut create: F) -> Self
where
F: FnMut(Filter, &'static str) -> T,
@@ -171,7 +207,8 @@ impl<T> ByAgeRange<T> {
let f = AGE_RANGE_FILTERS;
let n = AGE_RANGE_NAMES;
Self {
up_to_1d: create(f.up_to_1d.clone(), n.up_to_1d.id),
up_to_1h: create(f.up_to_1h.clone(), n.up_to_1h.id),
_1h_to_1d: create(f._1h_to_1d.clone(), n._1h_to_1d.id),
_1d_to_1w: create(f._1d_to_1w.clone(), n._1d_to_1w.id),
_1w_to_1m: create(f._1w_to_1m.clone(), n._1w_to_1m.id),
_1m_to_2m: create(f._1m_to_2m.clone(), n._1m_to_2m.id),
@@ -201,7 +238,8 @@ impl<T> ByAgeRange<T> {
let f = AGE_RANGE_FILTERS;
let n = AGE_RANGE_NAMES;
Ok(Self {
up_to_1d: create(f.up_to_1d.clone(), n.up_to_1d.id)?,
up_to_1h: create(f.up_to_1h.clone(), n.up_to_1h.id)?,
_1h_to_1d: create(f._1h_to_1d.clone(), n._1h_to_1d.id)?,
_1d_to_1w: create(f._1d_to_1w.clone(), n._1d_to_1w.id)?,
_1w_to_1m: create(f._1w_to_1m.clone(), n._1w_to_1m.id)?,
_1m_to_2m: create(f._1m_to_2m.clone(), n._1m_to_2m.id)?,
@@ -226,7 +264,8 @@ impl<T> ByAgeRange<T> {
pub fn iter(&self) -> impl Iterator<Item = &T> {
[
&self.up_to_1d,
&self.up_to_1h,
&self._1h_to_1d,
&self._1d_to_1w,
&self._1w_to_1m,
&self._1m_to_2m,
@@ -252,7 +291,8 @@ impl<T> ByAgeRange<T> {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self.up_to_1d,
&mut self.up_to_1h,
&mut self._1h_to_1d,
&mut self._1d_to_1w,
&mut self._1w_to_1m,
&mut self._1m_to_2m,
@@ -281,7 +321,8 @@ impl<T> ByAgeRange<T> {
T: Send + Sync,
{
[
&mut self.up_to_1d,
&mut self.up_to_1h,
&mut self._1h_to_1d,
&mut self._1d_to_1w,
&mut self._1w_to_1m,
&mut self._1m_to_2m,
@@ -305,4 +346,3 @@ impl<T> ByAgeRange<T> {
.into_par_iter()
}
}

View File

@@ -3,53 +3,53 @@ use rayon::prelude::*;
use serde::Serialize;
use super::{
CohortName, Filter, TimeFilter, DAYS_10Y, DAYS_12Y, DAYS_15Y, DAYS_1M, DAYS_1W, DAYS_1Y,
DAYS_2M, DAYS_2Y, DAYS_3M, DAYS_3Y, DAYS_4M, DAYS_4Y, DAYS_5M, DAYS_5Y, DAYS_6M, DAYS_6Y,
DAYS_7Y, DAYS_8Y,
CohortName, Filter, TimeFilter, HOURS_10Y, HOURS_12Y, HOURS_15Y, HOURS_1M, HOURS_1W, HOURS_1Y,
HOURS_2M, HOURS_2Y, HOURS_3M, HOURS_3Y, HOURS_4M, HOURS_4Y, HOURS_5M, HOURS_5Y, HOURS_6M,
HOURS_6Y, HOURS_7Y, HOURS_8Y,
};
/// Max age thresholds in days
pub const MAX_AGE_DAYS: ByMaxAge<usize> = ByMaxAge {
_1w: DAYS_1W,
_1m: DAYS_1M,
_2m: DAYS_2M,
_3m: DAYS_3M,
_4m: DAYS_4M,
_5m: DAYS_5M,
_6m: DAYS_6M,
_1y: DAYS_1Y,
_2y: DAYS_2Y,
_3y: DAYS_3Y,
_4y: DAYS_4Y,
_5y: DAYS_5Y,
_6y: DAYS_6Y,
_7y: DAYS_7Y,
_8y: DAYS_8Y,
_10y: DAYS_10Y,
_12y: DAYS_12Y,
_15y: DAYS_15Y,
/// Max age thresholds in hours
pub const MAX_AGE_HOURS: ByMaxAge<usize> = ByMaxAge {
_1w: HOURS_1W,
_1m: HOURS_1M,
_2m: HOURS_2M,
_3m: HOURS_3M,
_4m: HOURS_4M,
_5m: HOURS_5M,
_6m: HOURS_6M,
_1y: HOURS_1Y,
_2y: HOURS_2Y,
_3y: HOURS_3Y,
_4y: HOURS_4Y,
_5y: HOURS_5Y,
_6y: HOURS_6Y,
_7y: HOURS_7Y,
_8y: HOURS_8Y,
_10y: HOURS_10Y,
_12y: HOURS_12Y,
_15y: HOURS_15Y,
};
/// Max age filters (LowerThan threshold)
/// Max age filters (LowerThan threshold in hours)
pub const MAX_AGE_FILTERS: ByMaxAge<Filter> = ByMaxAge {
_1w: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._1w)),
_1m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._1m)),
_2m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._2m)),
_3m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._3m)),
_4m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._4m)),
_5m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._5m)),
_6m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._6m)),
_1y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._1y)),
_2y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._2y)),
_3y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._3y)),
_4y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._4y)),
_5y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._5y)),
_6y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._6y)),
_7y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._7y)),
_8y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._8y)),
_10y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._10y)),
_12y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._12y)),
_15y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_DAYS._15y)),
_1w: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._1w)),
_1m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._1m)),
_2m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._2m)),
_3m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._3m)),
_4m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._4m)),
_5m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._5m)),
_6m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._6m)),
_1y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._1y)),
_2y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._2y)),
_3y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._3y)),
_4y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._4y)),
_5y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._5y)),
_6y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._6y)),
_7y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._7y)),
_8y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._8y)),
_10y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._10y)),
_12y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._12y)),
_15y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._15y)),
};
/// Max age names

View File

@@ -3,53 +3,53 @@ use rayon::prelude::*;
use serde::Serialize;
use super::{
CohortName, Filter, TimeFilter, DAYS_10Y, DAYS_12Y, DAYS_1D, DAYS_1M, DAYS_1W, DAYS_1Y,
DAYS_2M, DAYS_2Y, DAYS_3M, DAYS_3Y, DAYS_4M, DAYS_4Y, DAYS_5M, DAYS_5Y, DAYS_6M, DAYS_6Y,
DAYS_7Y, DAYS_8Y,
CohortName, Filter, TimeFilter, HOURS_10Y, HOURS_12Y, HOURS_1D, HOURS_1M, HOURS_1W, HOURS_1Y,
HOURS_2M, HOURS_2Y, HOURS_3M, HOURS_3Y, HOURS_4M, HOURS_4Y, HOURS_5M, HOURS_5Y, HOURS_6M,
HOURS_6Y, HOURS_7Y, HOURS_8Y,
};
/// Min age thresholds in days
pub const MIN_AGE_DAYS: ByMinAge<usize> = ByMinAge {
_1d: DAYS_1D,
_1w: DAYS_1W,
_1m: DAYS_1M,
_2m: DAYS_2M,
_3m: DAYS_3M,
_4m: DAYS_4M,
_5m: DAYS_5M,
_6m: DAYS_6M,
_1y: DAYS_1Y,
_2y: DAYS_2Y,
_3y: DAYS_3Y,
_4y: DAYS_4Y,
_5y: DAYS_5Y,
_6y: DAYS_6Y,
_7y: DAYS_7Y,
_8y: DAYS_8Y,
_10y: DAYS_10Y,
_12y: DAYS_12Y,
/// Min age thresholds in hours
pub const MIN_AGE_HOURS: ByMinAge<usize> = ByMinAge {
_1d: HOURS_1D,
_1w: HOURS_1W,
_1m: HOURS_1M,
_2m: HOURS_2M,
_3m: HOURS_3M,
_4m: HOURS_4M,
_5m: HOURS_5M,
_6m: HOURS_6M,
_1y: HOURS_1Y,
_2y: HOURS_2Y,
_3y: HOURS_3Y,
_4y: HOURS_4Y,
_5y: HOURS_5Y,
_6y: HOURS_6Y,
_7y: HOURS_7Y,
_8y: HOURS_8Y,
_10y: HOURS_10Y,
_12y: HOURS_12Y,
};
/// Min age filters (GreaterOrEqual threshold)
/// Min age filters (GreaterOrEqual threshold in hours)
pub const MIN_AGE_FILTERS: ByMinAge<Filter> = ByMinAge {
_1d: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._1d)),
_1w: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._1w)),
_1m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._1m)),
_2m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._2m)),
_3m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._3m)),
_4m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._4m)),
_5m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._5m)),
_6m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._6m)),
_1y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._1y)),
_2y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._2y)),
_3y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._3y)),
_4y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._4y)),
_5y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._5y)),
_6y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._6y)),
_7y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._7y)),
_8y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._8y)),
_10y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._10y)),
_12y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_DAYS._12y)),
_1d: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._1d)),
_1w: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._1w)),
_1m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._1m)),
_2m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._2m)),
_3m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._3m)),
_4m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._4m)),
_5m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._5m)),
_6m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._6m)),
_1y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._1y)),
_2y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._2y)),
_3y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._3y)),
_4y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._4y)),
_5y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._5y)),
_6y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._6y)),
_7y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._7y)),
_8y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._8y)),
_10y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._10y)),
_12y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._12y)),
};
/// Min age names

View File

@@ -29,13 +29,13 @@ impl Filter {
}
}
/// Check if a time value (days) is contained by this filter
pub fn contains_time(&self, days: usize) -> bool {
/// Check if a time value (hours) is contained by this filter
pub fn contains_time(&self, hours: usize) -> bool {
match self {
Filter::All => true,
Filter::Term(Term::Sth) => days < Term::THRESHOLD_DAYS,
Filter::Term(Term::Lth) => days >= Term::THRESHOLD_DAYS,
Filter::Time(t) => t.contains(days),
Filter::Term(Term::Sth) => hours < Term::THRESHOLD_HOURS,
Filter::Term(Term::Lth) => hours >= Term::THRESHOLD_HOURS,
Filter::Time(t) => t.contains(hours),
_ => false,
}
}
@@ -54,12 +54,12 @@ impl Filter {
match (self, other) {
(Filter::All, _) => true,
(Filter::Term(Term::Sth), Filter::Time(t)) => {
matches!(t, TimeFilter::LowerThan(d) if *d <= Term::THRESHOLD_DAYS)
|| matches!(t, TimeFilter::Range(r) if r.end <= Term::THRESHOLD_DAYS)
matches!(t, TimeFilter::LowerThan(h) if *h <= Term::THRESHOLD_HOURS)
|| matches!(t, TimeFilter::Range(r) if r.end <= Term::THRESHOLD_HOURS)
}
(Filter::Term(Term::Lth), Filter::Time(t)) => {
matches!(t, TimeFilter::GreaterOrEqual(d) if *d >= Term::THRESHOLD_DAYS)
|| matches!(t, TimeFilter::Range(r) if r.start >= Term::THRESHOLD_DAYS)
matches!(t, TimeFilter::GreaterOrEqual(h) if *h >= Term::THRESHOLD_HOURS)
|| matches!(t, TimeFilter::Range(r) if r.start >= Term::THRESHOLD_HOURS)
}
(Filter::Time(t1), Filter::Time(t2)) => t1.includes(t2),
(Filter::Amount(a1), Filter::Amount(a2)) => a1.includes(a2),
@@ -89,17 +89,17 @@ impl Filter {
}
/// Whether to compute adjusted metrics (adjusted SOPR, adjusted value created/destroyed)
/// For UTXO context: true for All, Term, max_age (LowerThan), and up_to_1d age range
/// For UTXO context: true for All, STH, and max_age (LowerThan)
/// For Address context: always false
/// Note: LTH doesn't need adjusted (everything >= 5 months is already > 1 hour)
/// Note: age ranges don't need adjusted (0-1h data lives in its own cohort)
pub fn compute_adjusted(&self, context: CohortContext) -> bool {
match context {
CohortContext::Address => false,
CohortContext::Utxo => match self {
Filter::All | Filter::Term(_) => true,
Filter::Time(TimeFilter::LowerThan(_)) => true,
Filter::Time(TimeFilter::Range(r)) if r.start == 0 => true,
_ => false,
},
CohortContext::Utxo => matches!(
self,
Filter::All | Filter::Term(Term::Sth) | Filter::Time(TimeFilter::LowerThan(_))
),
}
}
}

View File

@@ -21,10 +21,11 @@ mod cohort_name;
mod filter;
mod filtered;
mod state_level;
mod term;
mod time_filter;
mod utxo;
pub use brk_types::{Age, Term};
pub use address::*;
pub use amount_filter::*;
pub use by_address_type::*;
@@ -33,7 +34,6 @@ pub use by_amount_range::*;
pub use by_any_address::*;
pub use by_epoch::*;
pub use by_ge_amount::*;
pub use by_year::*;
pub use by_lt_amount::*;
pub use by_max_age::*;
pub use by_min_age::*;
@@ -41,11 +41,11 @@ pub use by_spendable_type::*;
pub use by_term::*;
pub use by_type::*;
pub use by_unspendable_type::*;
pub use by_year::*;
pub use cohort_context::*;
pub use cohort_name::*;
pub use filter::*;
pub use filtered::*;
pub use state_level::*;
pub use term::*;
pub use time_filter::*;
pub use utxo::*;

View File

@@ -1,15 +0,0 @@
use crate::DAYS_5M;
/// Classification for short-term vs long-term holders.
/// The threshold is 150 days (approximately 5 months).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Term {
/// Short-Term Holder: < 150 days
Sth,
/// Long-Term Holder: >= 150 days
Lth,
}
impl Term {
pub const THRESHOLD_DAYS: usize = DAYS_5M;
}