crate_activity/
summary.rs1crate::ix!();
2
3#[derive(Builder,Debug)]
4#[builder(setter(into))]
5pub struct CrateActivitySummary {
6 date_interval_1d: NaiveDate,
7 date_interval_3d: NaiveDate,
8 date_interval_full_start: NaiveDate,
9 date_interval_full_end: NaiveDate,
10 total_downloads: i64,
11 avg_daily_downloads: f64,
12 avg_daily_downloads_per_crate: f64,
13 median_daily_downloads: i64,
14 crates_analyzed: usize,
15 top_crates_1d: Vec<(String, i64)>,
16 top_crates_3d: Vec<(String, i64)>,
17}
18
19impl fmt::Display for CrateActivitySummary {
20
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22
23 writeln!(f, "Crate Activity Summary:")?;
24 writeln!(f, " Full Data Range: {} to {}", self.date_interval_full_start, self.date_interval_full_end)?;
25 writeln!(f, " Date Interval (Last 1 Day): {}", self.date_interval_1d)?;
26 writeln!(f, " Date Interval (Last 3 Days): {}", self.date_interval_3d)?;
27
28 writeln!(f, " Total Downloads: {}", self.total_downloads)?;
29 writeln!(f, " Average Daily Downloads: {:.2}", self.avg_daily_downloads)?;
30 writeln!(f, " Average Daily Downloads per Crate: {:.2}", self.avg_daily_downloads_per_crate)?;
31 writeln!(f, " Median Daily Downloads: {}", self.median_daily_downloads)?;
32 writeln!(f, " Crates Analyzed: {}", self.crates_analyzed)?;
33
34 let mut total_1d_downloads = 0;
35 writeln!(f, "\nTop Crates (Last 1 Day):")?;
36 for (crate_name, downloads) in &self.top_crates_1d {
37 total_1d_downloads += downloads;
38 writeln!(f, " {:<30} {:>10} downloads", crate_name, downloads)?;
39 }
40 writeln!(f, " {:<30} total downloads (Last 1 Day)", total_1d_downloads)?;
41
42 let mut total_3d_downloads = 0;
43 writeln!(f, "\nTop Crates (Last 3 Days):")?;
44 for (crate_name, downloads) in &self.top_crates_3d {
45 total_3d_downloads += downloads;
46 writeln!(f, " {:<30} {:>10} downloads", crate_name, downloads)?;
47 }
48 writeln!(f, " {:<30} total downloads (Last 3 Days)", total_3d_downloads)?;
49
50 Ok(())
51 }
52}
53
54impl CrateActivitySummary {
55
56 pub fn new(
57 summaries: &[CrateUsageSummary],
58 interval_downloads_1d: HashMap<String, i64>,
59 interval_downloads_3d: HashMap<String, i64>,
60 one_day_ago: NaiveDate,
61 three_days_ago: NaiveDate,
62 ) -> Self {
63
64 let (full_start, full_end) = summaries
66 .iter()
67 .flat_map(|s| s.version_downloads())
68 .map(|d| d.date())
69 .minmax()
70 .into_option()
71 .unwrap_or((&one_day_ago, &one_day_ago));
72
73 let total_downloads: i64 = summaries.iter().map(|s| s.total_downloads()).sum();
75 let avg_daily_downloads: f64 = summaries.iter().map(|s| s.average_daily_downloads()).sum::<f64>();
76 let avg_daily_downloads_per_crate = avg_daily_downloads / summaries.len() as f64;
77
78 let mut daily_downloads: Vec<i64> = summaries.iter().map(|s| *s.total_downloads()).collect();
80 daily_downloads.sort();
81 let median_daily_downloads = if daily_downloads.is_empty() {
82 0
83 } else if daily_downloads.len() % 2 == 0 {
84 let mid = daily_downloads.len() / 2;
85 (daily_downloads[mid - 1] + daily_downloads[mid]) / 2
86 } else {
87 daily_downloads[daily_downloads.len() / 2]
88 };
89
90 let mut top_crates_1d: Vec<_> = interval_downloads_1d.into_iter().collect();
92 let mut top_crates_3d: Vec<_> = interval_downloads_3d.into_iter().collect();
93
94 top_crates_1d.sort_by_key(|&(_, downloads)| std::cmp::Reverse(downloads));
95 top_crates_3d.sort_by_key(|&(_, downloads)| std::cmp::Reverse(downloads));
96
97 CrateActivitySummary {
98 date_interval_1d: one_day_ago,
99 date_interval_3d: three_days_ago,
100 date_interval_full_end: *full_end,
101 date_interval_full_start: *full_start,
102 total_downloads,
103 avg_daily_downloads,
104 avg_daily_downloads_per_crate,
105 median_daily_downloads,
106 crates_analyzed: summaries.len(),
107 top_crates_1d,
108 top_crates_3d,
109 }
110 }
111}