1 | //! The module contains [`TruncateContent`] records iterator. |
2 | |
3 | use std::borrow::Cow; |
4 | |
5 | use crate::{ |
6 | grid::records::IntoRecords, grid::util::string::string_width_multiline, |
7 | settings::width::Truncate, |
8 | }; |
9 | |
10 | use super::either_string::EitherString; |
11 | |
12 | /// A records iterator which truncates all cells to a given width. |
13 | #[derive (Debug)] |
14 | pub struct TruncateContent<'a, I> { |
15 | records: I, |
16 | width: ExactValue<'a>, |
17 | } |
18 | |
19 | impl TruncateContent<'_, ()> { |
20 | /// Creates new [`TruncateContent`] object. |
21 | pub fn new<I: IntoRecords>(records: I, width: ExactValue<'_>) -> TruncateContent<'_, I> { |
22 | TruncateContent { records, width } |
23 | } |
24 | } |
25 | |
26 | impl<'a, I> IntoRecords for TruncateContent<'a, I> |
27 | where |
28 | I: IntoRecords, |
29 | { |
30 | type Cell = EitherString<I::Cell>; |
31 | type IterColumns = TruncateContentColumnsIter<'a, <I::IterColumns as IntoIterator>::IntoIter>; |
32 | type IterRows = TruncateContentIter<'a, <I::IterRows as IntoIterator>::IntoIter>; |
33 | |
34 | fn iter_rows(self) -> Self::IterRows { |
35 | TruncateContentIter { |
36 | iter: self.records.iter_rows().into_iter(), |
37 | width: self.width.clone(), |
38 | } |
39 | } |
40 | } |
41 | |
42 | /// A row iterator for [`TruncateContent`]. |
43 | #[derive (Debug)] |
44 | pub struct TruncateContentIter<'a, I> { |
45 | iter: I, |
46 | width: ExactValue<'a>, |
47 | } |
48 | |
49 | impl<'a, I> Iterator for TruncateContentIter<'a, I> |
50 | where |
51 | I: Iterator, |
52 | I::Item: IntoIterator, |
53 | <I::Item as IntoIterator>::Item: AsRef<str>, |
54 | { |
55 | type Item = TruncateContentColumnsIter<'a, <I::Item as IntoIterator>::IntoIter>; |
56 | |
57 | fn next(&mut self) -> Option<Self::Item> { |
58 | let iter: ::Item = self.iter.next()?; |
59 | Some(TruncateContentColumnsIter { |
60 | iter: iter.into_iter(), |
61 | current: 0, |
62 | width: self.width.clone(), |
63 | }) |
64 | } |
65 | } |
66 | |
67 | /// A column iterator for [`TruncateContent`]. |
68 | #[derive (Debug)] |
69 | pub struct TruncateContentColumnsIter<'a, I> { |
70 | iter: I, |
71 | width: ExactValue<'a>, |
72 | current: usize, |
73 | } |
74 | |
75 | impl<I> Iterator for TruncateContentColumnsIter<'_, I> |
76 | where |
77 | I: Iterator, |
78 | I::Item: AsRef<str>, |
79 | { |
80 | type Item = EitherString<I::Item>; |
81 | |
82 | fn next(&mut self) -> Option<Self::Item> { |
83 | let s: ::Item = self.iter.next()?; |
84 | |
85 | let width: usize = self.width.get(self.current); |
86 | self.current += 1; |
87 | |
88 | let text_width: usize = string_width_multiline(text:s.as_ref()); |
89 | if text_width <= width { |
90 | return Some(EitherString::Some(s)); |
91 | } |
92 | |
93 | let text: Cow<'_, str> = Truncate::truncate_text(text:s.as_ref(), width); |
94 | let text: String = text.into_owned(); |
95 | let text: EitherString<::Item> = EitherString::Owned(text); |
96 | |
97 | Some(text) |
98 | } |
99 | } |
100 | |
101 | /// A width value. |
102 | #[derive (Debug, Clone)] |
103 | pub enum ExactValue<'a> { |
104 | /// Const width value. |
105 | Exact(usize), |
106 | /// A list of width values for columns. |
107 | List(Cow<'a, [usize]>), |
108 | } |
109 | |
110 | impl<'a> From<&'a [usize]> for ExactValue<'a> { |
111 | fn from(value: &'a [usize]) -> Self { |
112 | Self::List(value.into()) |
113 | } |
114 | } |
115 | |
116 | impl From<Vec<usize>> for ExactValue<'_> { |
117 | fn from(value: Vec<usize>) -> Self { |
118 | Self::List(value.into()) |
119 | } |
120 | } |
121 | |
122 | impl From<usize> for ExactValue<'_> { |
123 | fn from(value: usize) -> Self { |
124 | Self::Exact(value) |
125 | } |
126 | } |
127 | |
128 | impl ExactValue<'_> { |
129 | /// Get a width by column. |
130 | pub fn get(&self, col: usize) -> usize { |
131 | match self { |
132 | ExactValue::Exact(val: &usize) => *val, |
133 | ExactValue::List(cols: &Cow<'_, [usize]>) => cols[col], |
134 | } |
135 | } |
136 | } |
137 | |