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 top_crates_7d: Vec<(String, i64)>,
18}
19
20impl fmt::Display for CrateActivitySummary {
21
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23
24 writeln!(f, "Crate Activity Summary:")?;
25 writeln!(f, " Full Data Range: {} to {}", self.date_interval_full_start, self.date_interval_full_end)?;
26 writeln!(f, " Date Interval (Last 1 Day): {}", self.date_interval_1d)?;
27 writeln!(f, " Date Interval (Last 3 Days): {}", self.date_interval_3d)?;
28
29 writeln!(f, " Total Downloads: {}", self.total_downloads)?;
30 writeln!(f, " Average Daily Downloads: {:.2}", self.avg_daily_downloads)?;
31 writeln!(f, " Average Daily Downloads per Crate: {:.2}", self.avg_daily_downloads_per_crate)?;
32 writeln!(f, " Median Daily Downloads: {}", self.median_daily_downloads)?;
33 writeln!(f, " Crates Analyzed: {}", self.crates_analyzed)?;
34
35 let mut total_1d_downloads = 0;
36 writeln!(f, "\nTop Crates (Last 1 Day):")?;
37 for (crate_name, downloads) in &self.top_crates_1d {
38 total_1d_downloads += downloads;
39 writeln!(f, " {:<30} {:>10} downloads", crate_name, downloads)?;
40 }
41 writeln!(f, " {:<30} total downloads (Last 1 Day)", total_1d_downloads)?;
42
43 let mut total_3d_downloads = 0;
44 writeln!(f, "\nTop Crates (Last 3 Days):")?;
45 for (crate_name, downloads) in &self.top_crates_3d {
46 total_3d_downloads += downloads;
47 writeln!(f, " {:<30} {:>10} downloads", crate_name, downloads)?;
48 }
49 writeln!(f, " {:<30} total downloads (Last 3 Days)", total_3d_downloads)?;
50
51 let mut total_7d_downloads = 0;
52 writeln!(f, "\nTop Crates (Last 7 Days):")?;
53 for (crate_name, downloads) in &self.top_crates_7d {
54 total_7d_downloads += downloads;
55 writeln!(f, " {:<30} {:>10} downloads", crate_name, downloads)?;
56 }
57 writeln!(f, " {:<30} total downloads (Last 7 Days)", total_7d_downloads)?;
58
59 Ok(())
60 }
61}
62
63impl CrateActivitySummary {
64
65 pub fn new(
66 summaries: &[CrateUsageSummary],
67 interval_downloads_1d: HashMap<String, i64>,
68 interval_downloads_3d: HashMap<String, i64>,
69 interval_downloads_7d: HashMap<String, i64>,
70 one_day_ago: NaiveDate,
71 three_days_ago: NaiveDate,
72 seven_days_ago: NaiveDate,
73 ) -> Self {
74
75 let (full_start, full_end) = summaries
77 .iter()
78 .flat_map(|s| s.version_downloads())
79 .map(|d| d.date())
80 .minmax()
81 .into_option()
82 .unwrap_or((&one_day_ago, &one_day_ago));
83
84 let total_downloads: i64 = summaries.iter().map(|s| s.total_downloads()).sum();
86 let avg_daily_downloads: f64 = summaries.iter().map(|s| s.average_daily_downloads()).sum::<f64>();
87 let avg_daily_downloads_per_crate = avg_daily_downloads / summaries.len() as f64;
88
89 let mut daily_downloads: Vec<i64> = summaries.iter().map(|s| *s.total_downloads()).collect();
91 daily_downloads.sort();
92 let median_daily_downloads = if daily_downloads.is_empty() {
93 0
94 } else if daily_downloads.len() % 2 == 0 {
95 let mid = daily_downloads.len() / 2;
96 (daily_downloads[mid - 1] + daily_downloads[mid]) / 2
97 } else {
98 daily_downloads[daily_downloads.len() / 2]
99 };
100
101 let mut top_crates_1d: Vec<_> = interval_downloads_1d.into_iter().collect();
103 let mut top_crates_3d: Vec<_> = interval_downloads_3d.into_iter().collect();
104 let mut top_crates_7d: Vec<_> = interval_downloads_7d.into_iter().collect();
105
106 top_crates_1d.sort_by_key(|&(_, downloads)| std::cmp::Reverse(downloads));
107 top_crates_3d.sort_by_key(|&(_, downloads)| std::cmp::Reverse(downloads));
108 top_crates_7d.sort_by_key(|&(_, downloads)| std::cmp::Reverse(downloads));
109
110 CrateActivitySummary {
111 date_interval_1d: one_day_ago,
112 date_interval_3d: three_days_ago,
113 date_interval_full_end: *full_end,
114 date_interval_full_start: *full_start,
115 total_downloads,
116 avg_daily_downloads,
117 avg_daily_downloads_per_crate,
118 median_daily_downloads,
119 crates_analyzed: summaries.len(),
120 top_crates_1d,
121 top_crates_3d,
122 top_crates_7d,
123 }
124 }
125}