lean_ctx/core/gain/
reach.rs1use serde::Serialize;
10
11#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
13pub struct ReachCounts {
14 pub routed_calls: u64,
15 pub native_passthrough_calls: u64,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
20#[serde(rename_all = "snake_case")]
21pub enum Unobserved {
22 Unknown,
23}
24
25#[derive(Debug, Clone, PartialEq, Serialize)]
26pub struct ReachView {
27 pub routed_calls: u64,
28 pub native_passthrough_calls: u64,
29 pub observed_calls: u64,
31 pub routed_pct_of_observed: Option<f64>,
33 pub unobserved_native_calls: Unobserved,
34}
35
36#[must_use]
37pub fn reach_view(counts: ReachCounts) -> ReachView {
38 let observed_calls = counts
39 .routed_calls
40 .saturating_add(counts.native_passthrough_calls);
41 ReachView {
42 routed_calls: counts.routed_calls,
43 native_passthrough_calls: counts.native_passthrough_calls,
44 observed_calls,
45 routed_pct_of_observed: (observed_calls > 0)
46 .then(|| counts.routed_calls as f64 * 100.0 / observed_calls as f64),
47 unobserved_native_calls: Unobserved::Unknown,
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn share_is_of_observed_calls_and_absent_without_observations() {
57 let none = reach_view(ReachCounts::default());
58 assert_eq!(none.observed_calls, 0);
59 assert_eq!(none.routed_pct_of_observed, None);
60
61 let view = reach_view(ReachCounts {
62 routed_calls: 9,
63 native_passthrough_calls: 1,
64 });
65 assert_eq!(view.observed_calls, 10);
66 assert_eq!(view.routed_pct_of_observed, Some(90.0));
67 let json = serde_json::to_value(&view).unwrap();
68 assert_eq!(json["unobserved_native_calls"], "unknown");
69 assert_eq!(json["routed_pct_of_observed"], 90.0);
70 }
71}