papergrid/records/
vec_records.rs

1//! The module contains a [`VecRecords`] implementation of [`Records`].
2
3use std::{
4    fmt::{self, Formatter},
5    ops::{Index, IndexMut},
6};
7
8use super::{cell_info::CellInfo, Records, RecordsMut, Resizable};
9use crate::{width::WidthFunc, Position};
10
11/// The structure represents a [`Records`] implementation as an pre built vector of cells.
12#[derive(Debug, Default, Clone)]
13pub struct VecRecords<T> {
14    records: Vec<Vec<T>>,
15    size: (usize, usize),
16}
17
18impl<'a> VecRecords<CellInfo<'a>> {
19    /// Builds a structure instance from an iterator.
20    pub fn new<R, C, T, W>(records: R, size: (usize, usize), width_ctrl: W) -> Self
21    where
22        R: IntoIterator<Item = C> + 'a,
23        C: IntoIterator<Item = T> + 'a,
24        T: AsRef<str> + 'a,
25        W: WidthFunc,
26    {
27        let records = create_records(records, width_ctrl, size);
28        Self { records, size }
29    }
30}
31
32impl<T> VecRecords<T> {
33    /// Builds a structure instance with using an exact columns length.
34    ///
35    /// WARNING: You must verify that provided records contains is bigger than or eqaull than provided hint value.
36    pub fn with_hint(records: Vec<Vec<T>>, count_columns: usize) -> Self {
37        let count_rows = records.len();
38        let size = (count_rows, count_columns);
39
40        Self { records, size }
41    }
42
43    /// Returns a shape of [`Records`].
44    pub fn size(&self) -> (usize, usize) {
45        self.size
46    }
47
48    /// Returns a count of rows.
49    pub fn count_rows(&self) -> usize {
50        self.size.0
51    }
52
53    /// Returns a count of columns.
54    pub fn count_columns(&self) -> usize {
55        self.size.1
56    }
57
58    /// Truncates columns to the given length.
59    pub fn truncate(&mut self, len: usize) {
60        if self.size.1 > len {
61            self.size.1 = len;
62            for row in &mut self.records {
63                row.truncate(len);
64            }
65        }
66    }
67}
68
69impl<T> VecRecords<T>
70where
71    T: Clone,
72{
73    /// Creates a column with a given cell.
74    ///
75    /// The cell will be cloned.
76    pub fn push(&mut self, cell: T) {
77        for row in &mut self.records {
78            row.push(cell.clone());
79        }
80
81        self.size.1 += 1;
82    }
83}
84
85impl<T> From<Vec<Vec<T>>> for VecRecords<T> {
86    fn from(records: Vec<Vec<T>>) -> Self {
87        let count_rows = records.len();
88        let count_cols = records.get(0).map_or(0, Vec::len);
89        let size = (count_rows, count_cols);
90
91        Self { records, size }
92    }
93}
94
95impl<T> VecRecords<T>
96where
97    T: Clone,
98{
99    /// Takes a row index and pushes the cloned row to the end.
100    pub fn duplicate_row(&mut self, row: usize) {
101        if row >= self.size.0 {
102            return;
103        }
104
105        let row = self.records[row].clone();
106        self.records.push(row);
107        self.size.0 += 1;
108    }
109}
110
111impl<T> Records for VecRecords<T>
112where
113    T: Cell,
114{
115    fn count_rows(&self) -> usize {
116        self.size.0
117    }
118
119    fn count_columns(&self) -> usize {
120        self.size.1
121    }
122
123    fn get_text(&self, (row, col): Position) -> &str {
124        self.records[row][col].as_ref()
125    }
126
127    fn get_line(&self, (row, col): Position, i: usize) -> &str {
128        self.records[row][col].get_line(i)
129    }
130
131    fn get_width<W>(&self, (row, col): Position, width_ctrl: W) -> usize
132    where
133        W: WidthFunc,
134    {
135        self.records[row][col].width(width_ctrl)
136    }
137
138    fn get_line_width<W>(&self, (row, col): Position, i: usize, width_ctrl: W) -> usize
139    where
140        W: WidthFunc,
141    {
142        self.records[row][col].line_width(i, width_ctrl)
143    }
144
145    fn count_lines(&self, (row, col): Position) -> usize {
146        self.records[row][col].count_lines()
147    }
148
149    fn fmt_text_prefix(
150        &self,
151        f: &mut std::fmt::Formatter<'_>,
152        (row, col): Position,
153    ) -> std::fmt::Result {
154        self.records[row][col].fmt_prefix(f)
155    }
156
157    fn fmt_text_suffix(
158        &self,
159        f: &mut std::fmt::Formatter<'_>,
160        (row, col): Position,
161    ) -> std::fmt::Result {
162        self.records[row][col].fmt_suffix(f)
163    }
164}
165
166impl<T, Q> RecordsMut<Q> for VecRecords<T>
167where
168    T: CellMut<Q>,
169{
170    fn set<W>(&mut self, (row, col): Position, text: Q, width_ctrl: W)
171    where
172        W: WidthFunc,
173    {
174        self.records[row][col].set(text, width_ctrl);
175    }
176
177    fn update<W>(&mut self, (row, col): Position, width_ctrl: W)
178    where
179        W: WidthFunc,
180    {
181        self.records[row][col].update(width_ctrl);
182    }
183}
184
185impl<T> Resizable for VecRecords<T>
186where
187    T: Default + Clone,
188{
189    fn swap(&mut self, lhs: Position, rhs: Position) {
190        if lhs.0 >= self.size.0
191            || lhs.1 >= self.size.1
192            || rhs.0 >= self.size.0
193            || rhs.1 >= self.size.1
194        {
195            return;
196        }
197
198        if lhs == rhs {
199            return;
200        }
201
202        let t = std::mem::take(&mut self.records[lhs.0][lhs.1]);
203        let t = std::mem::replace(&mut self.records[rhs.0][rhs.1], t);
204        let _ = std::mem::replace(&mut self.records[lhs.0][lhs.1], t);
205    }
206
207    fn swap_row(&mut self, lhs: usize, rhs: usize) {
208        if lhs >= self.size.0 || rhs >= self.size.0 {
209            return;
210        }
211
212        let t = std::mem::take(&mut self.records[lhs]);
213        let t = std::mem::replace(&mut self.records[rhs], t);
214        let _ = std::mem::replace(&mut self.records[lhs], t);
215    }
216
217    fn swap_column(&mut self, lhs: usize, rhs: usize) {
218        if lhs >= self.size.1 || rhs >= self.size.1 {
219            return;
220        }
221
222        for row in &mut self.records {
223            row.swap(lhs, rhs);
224        }
225    }
226
227    fn push_row(&mut self) {
228        self.size.0 += 1;
229        self.records.push(vec![T::default(); self.size.1]);
230    }
231
232    fn push_column(&mut self) {
233        self.size.1 += 1;
234        for row in &mut self.records {
235            row.push(T::default());
236        }
237    }
238
239    fn remove_row(&mut self, row: usize) {
240        if row >= self.records.len() {
241            return;
242        }
243
244        self.records.remove(row);
245        self.size.0 -= 1;
246    }
247
248    fn remove_column(&mut self, column: usize) {
249        if column >= self.size.1 {
250            return;
251        }
252
253        for row in &mut self.records {
254            row.remove(column);
255        }
256        self.size.1 -= 1;
257    }
258
259    fn insert_row(&mut self, row: usize) {
260        self.records.insert(row, vec![T::default(); self.size.1]);
261    }
262}
263
264impl<T> Index<Position> for VecRecords<T> {
265    type Output = T;
266
267    fn index(&self, (row, col): Position) -> &Self::Output {
268        &self.records[row][col]
269    }
270}
271
272impl<T> IndexMut<Position> for VecRecords<T> {
273    fn index_mut(&mut self, (row, col): Position) -> &mut Self::Output {
274        &mut self.records[row][col]
275    }
276}
277
278fn create_records<'a, I, T, S, W>(
279    data: I,
280    width_ctrl: W,
281    (hint_count_rows, hint_count_cols): (usize, usize),
282) -> Vec<Vec<CellInfo<'a>>>
283where
284    I: IntoIterator<Item = T>,
285    T: IntoIterator<Item = S>,
286    S: AsRef<str> + 'a,
287    W: WidthFunc,
288{
289    let mut cells = vec![vec![CellInfo::default(); hint_count_cols]; hint_count_rows];
290    let mut count_rows = hint_count_rows;
291
292    for (row, rows) in data.into_iter().enumerate() {
293        if row >= count_rows {
294            cells.push(vec![CellInfo::default(); hint_count_cols]);
295            count_rows += 1;
296        }
297
298        for (col, text) in rows.into_iter().enumerate().take(hint_count_cols) {
299            let text = text.as_ref();
300            if text.is_empty() {
301                continue;
302            }
303
304            cells[row][col] = CellInfo::new(text.to_owned(), &width_ctrl);
305        }
306    }
307
308    cells
309}
310
311/// Cell imlementation which can be used with [`VecRecords`].
312pub trait Cell: AsRef<str> {
313    /// Gets a line by index.
314    fn get_line(&self, i: usize) -> &str;
315
316    /// Returns a number of lines cell has.
317    fn count_lines(&self) -> usize;
318
319    /// Returns a width of cell.
320    fn width<W>(&self, width_ctrl: W) -> usize
321    where
322        W: WidthFunc;
323
324    /// Returns a width of cell line.
325    fn line_width<W>(&self, i: usize, width_ctrl: W) -> usize
326    where
327        W: WidthFunc;
328
329    /// Prints a prefix.
330    ///
331    /// It might be usefull when used for ANSI prefix.
332    fn fmt_prefix(&self, _: &mut Formatter<'_>) -> fmt::Result {
333        Ok(())
334    }
335
336    /// Prints a suffix.
337    ///
338    /// It might be usefull when used for ANSI suffix.
339    fn fmt_suffix(&self, _: &mut Formatter<'_>) -> fmt::Result {
340        Ok(())
341    }
342}
343
344/// Cell representation of [`VecRecords`] which can be modified.
345pub trait CellMut<T> {
346    /// Sets a text to a cell.
347    fn set<W>(&mut self, text: T, width_ctrl: W)
348    where
349        W: WidthFunc;
350
351    /// Trigers an update a cell.
352    ///
353    /// It may be caused if width function was changed.
354    fn update<W>(&mut self, width_ctrl: W)
355    where
356        W: WidthFunc;
357}