1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use ;
use Future;
use ;
use crateAggregate;
/// A [`Report`] represents the processed form of an [`Aggregate`].
///
/// Reports transform raw aggregated data into meaningful insights — such as
/// averages, percentiles, ratios, and totals. They are *pure data structures*, free
/// of side effects and I/O, and should encapsulate only the logic needed to derive
/// final, human- or machine-readable results.
///
/// Implementors must define how to construct the report from an [`Aggregate`], typically
/// via a [`From<A>`] implementation. Once created, a report can be serialized, logged,
/// or consumed by a [`Reporter`].
///
/// # Design goals
/// - **Purity:** reports contain no I/O; they are deterministic data transformations.
/// - **Serializability:** all reports must implement [`Serialize`] and [`DeserializeOwned`].
/// - **Composability:** the same aggregate type can feed multiple report implementations
/// with different analytical focuses.
///
/// # Example
/// ```rust, ignore
/// use karga::{Aggregate, Report};
/// use serde::{Serialize, Deserialize};
/// use std::time::Duration;
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct MyReport {
/// average_latency: Duration,
/// }
///
/// impl From<MyAggregate> for MyReport {
/// fn from(a: MyAggregate) -> Self {
/// Self { average_latency: a.total_latency / a.count as u32 }
/// }
/// }
///
/// impl Report<MyAggregate> for MyReport {}
/// ```
///
/// # Feature flags
/// - `builtins`: includes [`BasicReport`], a ready-to-use implementation derived
/// from [`BasicAggregate`](crate::aggregate::BasicAggregate).
///
/// See also: [`Reporter`].
/// A [`Reporter`] consumes a [`Report`] and performs side effects — displaying it,
/// sending it to a service, or persisting it somewhere.
///
/// Reporters represent the I/O boundary of Karga. They may be synchronous or async,
/// and can target multiple destinations. This separation allows the computation layer
/// (metrics → aggregates → reports) to remain pure and deterministic, while reporters
/// handle presentation and export.
///
/// # Example
/// ```rust
/// use karga::{Reporter, Aggregate, Report};
/// struct MyReporter;
/// impl<A: Aggregate, R: Report<A>> Reporter<A, R> for MyReporter {
/// async fn report(&self, report: &R) -> Result<(), Box<dyn std::error::Error>> {
/// println!("{:?}", report);
/// Ok(())
/// }
/// }
/// ```
pub use *;