rustup_available_packages/
table.rs1use crate::availability::{AvailabilityData, AvailabilityRow};
4use chrono::NaiveDate;
5use std::{borrow::Borrow, iter};
6
7#[derive(Debug, serde::Serialize)]
9pub struct Table<'a, Additional: 'a = ()> {
10 pub current_target: &'a str,
12 pub title: Vec<String>,
14 pub packages_availability: Vec<AvailabilityRow<'a>>,
16 pub additional: Additional,
18}
19
20fn sort<T: Ord>(data: impl IntoIterator<Item = T>) -> Vec<T> {
23 let mut vec: Vec<_> = data.into_iter().collect();
24 vec.sort_unstable();
25 vec
26}
27
28#[derive(Debug, Clone)]
30pub struct TableBuilder<'a, Dates = iter::Empty<NaiveDate>, DateFmt = &'static str, Additional = ()>
31{
32 data: &'a AvailabilityData,
33 target: &'a str,
34 dates: Dates,
35 first_cell: String,
36 date_fmt: DateFmt,
37 additional_data: Additional,
38}
39
40impl<'a> TableBuilder<'a> {
41 pub fn default(data: &'a AvailabilityData, target: &'a str) -> Self {
46 TableBuilder {
47 data,
48 target,
49 dates: iter::empty(),
50 first_cell: String::new(),
51 date_fmt: "%Y-%m-%d",
52 additional_data: (),
53 }
54 }
55}
56
57impl<'a, Dates, DateFmt, Additional> TableBuilder<'a, Dates, DateFmt, Additional> {
58 pub fn first_cell(self, first_cell: &impl ToString) -> Self {
60 TableBuilder {
61 first_cell: first_cell.to_string(),
62 ..self
63 }
64 }
65
66 pub fn dates<I>(self, dates: I) -> TableBuilder<'a, I::IntoIter, DateFmt, Additional>
71 where
72 I: IntoIterator,
73 I::IntoIter: Clone,
74 I::Item: Borrow<NaiveDate>,
75 {
76 TableBuilder {
77 data: self.data,
78 target: self.target,
79 dates: dates.into_iter(),
80 first_cell: self.first_cell,
81 date_fmt: self.date_fmt,
82 additional_data: self.additional_data,
83 }
84 }
85
86 pub fn date_format<T>(self, date_fmt: T) -> TableBuilder<'a, Dates, T, Additional>
92 where
93 T: AsRef<str>,
94 {
95 TableBuilder {
96 data: self.data,
97 target: self.target,
98 dates: self.dates,
99 first_cell: self.first_cell,
100 date_fmt,
101 additional_data: self.additional_data,
102 }
103 }
104
105 pub fn additional<NewAdditional>(
107 self,
108 data: NewAdditional,
109 ) -> TableBuilder<'a, Dates, DateFmt, NewAdditional> {
110 TableBuilder {
111 data: self.data,
112 target: self.target,
113 dates: self.dates,
114 first_cell: self.first_cell,
115 date_fmt: self.date_fmt,
116 additional_data: data,
117 }
118 }
119
120 pub fn build(self) -> Table<'a, Additional>
122 where
123 Dates: Iterator + Clone,
124 Dates::Item: Borrow<NaiveDate>,
125 DateFmt: AsRef<str>,
126 {
127 Table::new(
128 self.data,
129 self.target,
130 &self.dates,
131 self.first_cell,
132 self.date_fmt.as_ref(),
133 self.additional_data,
134 )
135 }
136}
137
138impl<'a> Table<'a> {
139 pub fn builder(data: &'a AvailabilityData, target: &'a str) -> TableBuilder<'a> {
141 TableBuilder::default(data, target)
142 }
143}
144
145impl<'a, Additional> Table<'a, Additional> {
146 fn new<I>(
148 data: &'a AvailabilityData,
149 target: &'a str,
150 dates: &I,
151 first_cell: String,
152 date_fmt: &str,
153 additional_data: Additional,
154 ) -> Self
155 where
156 I: Iterator + Clone,
157 I::Item: Borrow<NaiveDate>,
158 {
159 let title = iter::once(first_cell)
160 .chain(
161 dates
162 .clone()
163 .map(|date| date.borrow().format(date_fmt).to_string()),
164 )
165 .collect();
166 let packages = sort(data.get_available_packages());
167 let availability = packages
168 .into_iter()
169 .filter_map(|pkg| data.get_availability_row(target, pkg, dates.clone()))
170 .collect();
171 Table {
172 current_target: target,
173 title,
174 packages_availability: availability,
175 additional: additional_data,
176 }
177 }
178}