1//! The module contains [`TruncateContent`] records iterator.
2
3use std::borrow::Cow;
4
5use crate::{
6 grid::records::IntoRecords, grid::util::string::string_width_multiline,
7 settings::width::Truncate,
8};
9
10use super::either_string::EitherString;
11
12/// A records iterator which truncates all cells to a given width.
13#[derive(Debug)]
14pub struct TruncateContent<'a, I> {
15 records: I,
16 width: ExactValue<'a>,
17}
18
19impl 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
26impl<'a, I> IntoRecords for TruncateContent<'a, I>
27where
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)]
44pub struct TruncateContentIter<'a, I> {
45 iter: I,
46 width: ExactValue<'a>,
47}
48
49impl<'a, I> Iterator for TruncateContentIter<'a, I>
50where
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)]
69pub struct TruncateContentColumnsIter<'a, I> {
70 iter: I,
71 width: ExactValue<'a>,
72 current: usize,
73}
74
75impl<I> Iterator for TruncateContentColumnsIter<'_, I>
76where
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)]
103pub 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
110impl<'a> From<&'a [usize]> for ExactValue<'a> {
111 fn from(value: &'a [usize]) -> Self {
112 Self::List(value.into())
113 }
114}
115
116impl From<Vec<usize>> for ExactValue<'_> {
117 fn from(value: Vec<usize>) -> Self {
118 Self::List(value.into())
119 }
120}
121
122impl From<usize> for ExactValue<'_> {
123 fn from(value: usize) -> Self {
124 Self::Exact(value)
125 }
126}
127
128impl 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