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
use std::sync::Arc;
use serde::Serialize;
use crate::t_println;
use super::OutputType;
use super::TableOutputHandler;
use super::KeyValOutputHandler;
use super::OutputError;
use super::Terminal;
pub trait DescribeObjectHandler {
fn is_ok(&self) -> bool;
fn is_error(&self) -> bool;
fn validate(&self) -> Result<(), OutputError>;
fn label() -> &'static str;
fn label_plural() -> &'static str;
}
pub struct DescribeObjectRender<O>(Arc<O>);
impl<O> DescribeObjectRender<O> {
pub fn new(out: Arc<O>) -> Self {
Self(out)
}
}
impl<O: Terminal> DescribeObjectRender<O> {
pub fn render<D>(&self, objects: &[D], output_type: OutputType) -> Result<(), OutputError>
where
D: DescribeObjectHandler + TableOutputHandler + KeyValOutputHandler + Serialize + Clone,
{
let out = self.0.clone();
if output_type.is_table() {
self.print_table(objects)
} else {
out.render_serde(&objects.to_vec(), output_type.into())
}
}
pub fn print_table<D>(&self, objects: &[D]) -> Result<(), OutputError>
where
D: DescribeObjectHandler + TableOutputHandler + KeyValOutputHandler,
{
match objects.len() {
1 => {
let object = &objects[0];
object.validate()?;
self.0.render_key_values(object);
self.0.clone().render_table(object, true);
}
_ => {
println!("{}", self.header_summary(objects));
for object in objects {
if object.is_ok() {
t_println!(self.0, "");
println!("{} DETAILS", D::label().to_ascii_uppercase());
println!("-------------");
self.0.render_key_values(object);
self.0.clone().render_table(object, true);
}
}
}
}
Ok(())
}
fn header_summary<D>(&self, objects: &[D]) -> String
where
D: DescribeObjectHandler,
{
let all_cnt = objects.len();
let mut ok_cnt = 0;
let mut err_cnt = 0;
for object in objects {
if object.is_ok() {
ok_cnt += 1;
} else if object.is_error() {
err_cnt += 1;
}
}
let invalid_cnt = all_cnt - (ok_cnt + err_cnt);
if invalid_cnt > 0 {
format!(
"Retrieved {} out of {} {} ({} are invalid)",
ok_cnt,
all_cnt,
D::label_plural(),
invalid_cnt
)
} else {
format!(
"Retrieved {} out of {} {}",
ok_cnt,
all_cnt,
D::label_plural()
)
}
}
}