1 | use std::borrow::Cow; |
2 | |
3 | /// Tabled a trait responsible for providing a header fields and a row fields. |
4 | /// |
5 | /// It's urgent that `header` len is equal to `fields` len. |
6 | /// |
7 | /// ```text |
8 | /// Self::headers().len() == self.fields().len() |
9 | /// ``` |
10 | pub trait Tabled { |
11 | /// A length of fields and headers, |
12 | /// which must be the same. |
13 | const LENGTH: usize; |
14 | |
15 | /// Fields method must return a list of cells. |
16 | /// |
17 | /// The cells will be placed in the same row, preserving the order. |
18 | fn fields(&self) -> Vec<Cow<'_, str>>; |
19 | /// Headers must return a list of column names. |
20 | fn headers() -> Vec<Cow<'static, str>>; |
21 | } |
22 | |
23 | impl<T> Tabled for &T |
24 | where |
25 | T: Tabled, |
26 | { |
27 | const LENGTH: usize = T::LENGTH; |
28 | |
29 | fn fields(&self) -> Vec<Cow<'_, str>> { |
30 | T::fields(self) |
31 | } |
32 | fn headers() -> Vec<Cow<'static, str>> { |
33 | T::headers() |
34 | } |
35 | } |
36 | |
37 | impl<T> Tabled for Box<T> |
38 | where |
39 | T: Tabled, |
40 | { |
41 | const LENGTH: usize = T::LENGTH; |
42 | |
43 | fn fields(&self) -> Vec<Cow<'_, str>> { |
44 | T::fields(self) |
45 | } |
46 | fn headers() -> Vec<Cow<'static, str>> { |
47 | T::headers() |
48 | } |
49 | } |
50 | |
51 | macro_rules! tuple_table { |
52 | ( $($name:ident)+ ) => { |
53 | impl<$($name: Tabled),+> Tabled for ($($name,)+){ |
54 | const LENGTH: usize = $($name::LENGTH+)+ 0; |
55 | |
56 | fn fields(&self) -> Vec<Cow<'_, str>> { |
57 | #![allow(non_snake_case)] |
58 | let ($($name,)+) = self; |
59 | let mut fields = Vec::with_capacity(Self::LENGTH); |
60 | $(fields.append(&mut $name.fields());)+ |
61 | fields |
62 | } |
63 | |
64 | fn headers() -> Vec<Cow<'static, str>> { |
65 | let mut fields = Vec::with_capacity(Self::LENGTH); |
66 | $(fields.append(&mut $name::headers());)+ |
67 | fields |
68 | } |
69 | } |
70 | }; |
71 | } |
72 | |
73 | tuple_table! { A } |
74 | tuple_table! { A B } |
75 | tuple_table! { A B C } |
76 | tuple_table! { A B C D } |
77 | tuple_table! { A B C D E } |
78 | tuple_table! { A B C D E F } |
79 | |
80 | macro_rules! default_table { |
81 | ( $t:ty ) => { |
82 | impl Tabled for $t { |
83 | const LENGTH: usize = 1; |
84 | |
85 | fn fields(&self) -> Vec<Cow<'_, str>> { |
86 | vec![Cow::Owned(self.to_string())] |
87 | } |
88 | fn headers() -> Vec<Cow<'static, str>> { |
89 | vec![Cow::Borrowed(stringify!($t))] |
90 | } |
91 | } |
92 | }; |
93 | |
94 | ( $t:ty = borrowed ) => { |
95 | impl Tabled for $t { |
96 | const LENGTH: usize = 1; |
97 | |
98 | fn fields(&self) -> Vec<Cow<'_, str>> { |
99 | vec![Cow::Borrowed(self)] |
100 | } |
101 | fn headers() -> Vec<Cow<'static, str>> { |
102 | vec![Cow::Borrowed(stringify!($t))] |
103 | } |
104 | } |
105 | }; |
106 | } |
107 | |
108 | default_table!(&str = borrowed); |
109 | default_table!(str = borrowed); |
110 | default_table!(String); |
111 | |
112 | default_table!(char); |
113 | |
114 | default_table!(bool); |
115 | |
116 | default_table!(isize); |
117 | default_table!(usize); |
118 | |
119 | default_table!(u8); |
120 | default_table!(u16); |
121 | default_table!(u32); |
122 | default_table!(u64); |
123 | default_table!(u128); |
124 | |
125 | default_table!(i8); |
126 | default_table!(i16); |
127 | default_table!(i32); |
128 | default_table!(i64); |
129 | default_table!(i128); |
130 | |
131 | default_table!(f32); |
132 | default_table!(f64); |
133 | |
134 | impl<T, const N: usize> Tabled for [T; N] |
135 | where |
136 | T: std::fmt::Display, |
137 | { |
138 | const LENGTH: usize = N; |
139 | |
140 | fn fields(&self) -> Vec<Cow<'_, str>> { |
141 | self.iter() |
142 | .map(ToString::to_string) |
143 | .map(Cow::Owned) |
144 | .collect() |
145 | } |
146 | |
147 | fn headers() -> Vec<Cow<'static, str>> { |
148 | (0..N).map(|i: usize| Cow::Owned(format!(" {i}" ))).collect() |
149 | } |
150 | } |
151 | |