ocpi_tariffs_cli/
print.rs1use std::fmt::{self, Write as _};
2
3use console::{measure_text_width, style};
4use ocpi_tariffs::UnknownFields;
5
6const LINE: &str = "----------------------------------------------------------------";
8const TABLE_BUF_LEN: usize = 4096;
10
11pub fn unknown_cdr_fields(unknown_fields: UnknownFields) {
13 if unknown_fields.is_empty() {
14 return;
15 }
16
17 eprintln!(
18 "{}: {} Unknown fields found in the CDR",
19 style("WARN").yellow(),
20 unknown_fields.len(),
21 );
22
23 for field_name in unknown_fields {
24 eprintln!(" - {}", style(field_name).yellow());
25 }
26
27 let line = style(LINE).yellow();
28 eprintln!("{line}");
29}
30
31pub fn unknown_tariff_fields(unknown_fields: Vec<(String, UnknownFields)>) {
33 if unknown_fields
34 .iter()
35 .all(|(_, unknown_fields)| unknown_fields.is_empty())
36 {
37 return;
38 }
39
40 let line = style(LINE).yellow();
41
42 eprintln!(
43 "{}: Unknown fields found in the tariffs",
44 style("WARN").yellow(),
45 );
46
47 for (tariff_id, unknown_fields) in unknown_fields {
48 if unknown_fields.is_empty() {
49 continue;
50 }
51
52 eprintln!(
53 "{}: {} Unknown fields found in the tariff with id: {}",
54 style("WARN").yellow(),
55 unknown_fields.len(),
56 style(tariff_id).yellow(),
57 );
58
59 for field_name in unknown_fields {
60 eprintln!(" - {}", style(field_name).yellow());
61 }
62
63 eprintln!("{line}");
64 }
65
66 eprintln!("{line}");
67}
68
69pub struct Table {
71 widths: Vec<usize>,
73 buf: String,
75}
76
77pub(crate) struct Col<'a> {
79 pub(crate) label: &'a dyn fmt::Display,
80 pub(crate) width: usize,
81}
82
83impl Col<'_> {
84 pub(crate) fn empty(width: usize) -> Self {
85 Self { label: &"", width }
86 }
87}
88
89impl Table {
90 pub fn header(header: &[Col<'_>]) -> Self {
92 let widths = header
93 .iter()
94 .map(|Col { label: _, width }| *width)
95 .collect::<Vec<_>>();
96 let mut buf = String::with_capacity(TABLE_BUF_LEN);
97 let labels = header
98 .iter()
99 .map(|Col { label, width: _ }| *label)
100 .collect::<Vec<_>>();
101
102 print_table_line(&mut buf, &widths);
103 print_table_row(&mut buf, &widths, &labels);
104 print_table_line(&mut buf, &widths);
105
106 Self { widths, buf }
107 }
108
109 pub fn print_line(&mut self) {
111 print_table_line(&mut self.buf, &self.widths);
112 }
113
114 pub fn print_row(&mut self, values: &[&dyn fmt::Display]) {
116 print_table_row(&mut self.buf, &self.widths, values);
117 }
118
119 pub fn print_valid_row(
124 &mut self,
125 is_valid: bool,
126 label: &'static str,
127 values: &[&dyn fmt::Display],
128 ) {
129 let label = if is_valid {
130 style(label).green()
131 } else {
132 style(label).red()
133 };
134 print_table_row_with_label(&mut self.buf, &self.widths, &label, values);
135 }
136
137 pub fn finish(self) -> String {
139 let Self { widths, mut buf } = self;
140 print_table_line(&mut buf, &widths);
141 buf
142 }
143}
144
145#[macro_export]
152macro_rules! write_or {
153 ($dst:expr, $($arg:tt)*) => {{
154 let _ignore_result = $dst.write_fmt(std::format_args!($($arg)*));
155 }};
156}
157
158fn print_table_line(buf: &mut String, widths: &[usize]) {
160 write_or!(buf, "+");
161
162 for width in widths {
163 write_or!(buf, "{0:->1$}+", "", width + 2);
164 }
165
166 write_or!(buf, "\n");
167}
168
169fn print_table_row(buf: &mut String, widths: &[usize], values: &[&dyn fmt::Display]) {
171 assert_eq!(
172 widths.len(),
173 values.len(),
174 "The widths and values amounts should be the same"
175 );
176 print_table_row_(buf, widths, values, None);
177}
178
179fn print_table_row_with_label(
183 buf: &mut String,
184 widths: &[usize],
185 label: &dyn fmt::Display,
186 values: &[&dyn fmt::Display],
187) {
188 print_table_row_(buf, widths, values, Some(label));
189}
190
191fn print_table_row_(
193 buf: &mut String,
194 widths: &[usize],
195 values: &[&dyn fmt::Display],
196 label: Option<&dyn fmt::Display>,
197) {
198 write_or!(buf, "|");
199
200 if let Some(label) = label {
201 let mut widths = widths.iter();
202 let Some(width) = widths.next() else {
203 return;
204 };
205 print_col(buf, label, *width);
206
207 for (value, width) in values.iter().zip(widths) {
208 print_col(buf, *value, *width);
209 }
210 } else {
211 for (value, width) in values.iter().zip(widths) {
212 print_col(buf, *value, *width);
213 }
214 }
215
216 write_or!(buf, "\n");
217}
218
219fn print_col(buf: &mut String, value: &dyn fmt::Display, width: usize) {
221 write_or!(buf, " ");
222
223 let len_before = buf.len();
226 write_or!(buf, "{value}");
227 let len_after = buf.len();
228
229 let s = &buf[len_before..len_after];
232 let len = measure_text_width(s);
233 let padding = width.saturating_sub(len);
235
236 for _ in 0..padding {
238 write_or!(buf, " ");
239 }
240
241 write_or!(buf, " |");
242}