Coverage Report

Created: 2026-07-30 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/papergrid-0.18.0/src/dimension/peekable.rs
Line
Count
Source
1
//! The module contains a [`PeekableGridDimension`].
2
3
use std::{
4
    cmp::{max, Ordering},
5
    collections::HashMap,
6
};
7
8
use crate::{
9
    config::{spanned::SpannedConfig, Position},
10
    dimension::{Dimension, Estimate},
11
    records::{vec_records::Cell, IntoRecords, Records},
12
};
13
14
/// A [`Dimension`] implementation which calculates exact column/row width/height for [`Records`] which used [`Cell`] cells.
15
///
16
/// It is a specialization of [`IterGridDimension`].
17
///
18
/// [`IterGridDimension`]: crate::dimension::iterable::IterGridDimension
19
#[derive(Debug, Default, Clone, PartialEq, Eq)]
20
pub struct PeekableGridDimension {
21
    height: Vec<usize>,
22
    width: Vec<usize>,
23
}
24
25
impl PeekableGridDimension {
26
    /// Calculates height of rows.
27
0
    pub fn height<R>(records: R, cfg: &SpannedConfig) -> Vec<usize>
28
0
    where
29
0
        R: Records,
30
0
        <R::Iter as IntoRecords>::Cell: Cell,
31
    {
32
0
        build_height(records, cfg)
33
0
    }
Unexecuted instantiation: <papergrid::dimension::peekable::PeekableGridDimension>::height::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: <papergrid::dimension::peekable::PeekableGridDimension>::height::<_>
34
35
    /// Calculates width of columns.
36
0
    pub fn width<R>(records: R, cfg: &SpannedConfig) -> Vec<usize>
37
0
    where
38
0
        R: Records,
39
0
        <R::Iter as IntoRecords>::Cell: Cell,
40
    {
41
0
        build_width(records, cfg)
42
0
    }
Unexecuted instantiation: <papergrid::dimension::peekable::PeekableGridDimension>::width::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: <papergrid::dimension::peekable::PeekableGridDimension>::width::<_>
43
44
    /// Calculates width of columns.
45
0
    pub fn dimension<R>(records: R, cfg: &SpannedConfig) -> (Vec<usize>, Vec<usize>)
46
0
    where
47
0
        R: Records,
48
0
        <R::Iter as IntoRecords>::Cell: Cell,
49
    {
50
0
        build_dimensions(records, cfg)
51
0
    }
Unexecuted instantiation: <papergrid::dimension::peekable::PeekableGridDimension>::dimension::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: <papergrid::dimension::peekable::PeekableGridDimension>::dimension::<_>
52
53
    /// Return width and height lists.
54
0
    pub fn get_values(self) -> (Vec<usize>, Vec<usize>) {
55
0
        (self.width, self.height)
56
0
    }
57
}
58
59
impl Dimension for PeekableGridDimension {
60
0
    fn get_width(&self, column: usize) -> usize {
61
0
        self.width[column]
62
0
    }
63
64
0
    fn get_height(&self, row: usize) -> usize {
65
0
        self.height[row]
66
0
    }
67
}
68
69
impl<R> Estimate<R, SpannedConfig> for PeekableGridDimension
70
where
71
    R: Records,
72
    <R::Iter as IntoRecords>::Cell: Cell,
73
{
74
0
    fn estimate(&mut self, records: R, cfg: &SpannedConfig) {
75
0
        let (width, height) = build_dimensions(records, cfg);
76
0
        self.width = width;
77
0
        self.height = height;
78
0
    }
Unexecuted instantiation: <papergrid::dimension::peekable::PeekableGridDimension as papergrid::dimension::Estimate<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>, papergrid::config::spanned::SpannedConfig>>::estimate
Unexecuted instantiation: <papergrid::dimension::peekable::PeekableGridDimension as papergrid::dimension::Estimate<_, papergrid::config::spanned::SpannedConfig>>::estimate
79
}
80
81
0
fn build_dimensions<R>(records: R, cfg: &SpannedConfig) -> (Vec<usize>, Vec<usize>)
82
0
where
83
0
    R: Records,
84
0
    <R::Iter as IntoRecords>::Cell: Cell,
85
{
86
0
    if cfg.has_column_spans() || cfg.has_row_spans() {
87
0
        build_dimensions_spanned(records, cfg)
88
    } else {
89
0
        build_dimensions_basic(records, cfg)
90
    }
91
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_dimensions::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_dimensions::<_>
92
93
0
fn build_dimensions_basic<R>(records: R, cfg: &SpannedConfig) -> (Vec<usize>, Vec<usize>)
94
0
where
95
0
    R: Records,
96
0
    <R::Iter as IntoRecords>::Cell: Cell,
97
{
98
0
    let count_columns = records.count_columns();
99
100
0
    let mut widths = vec![0; count_columns];
101
0
    let mut heights = vec![];
102
0
    if let Some(count_rows) = records.hint_count_rows() {
103
0
        heights.reserve(count_rows);
104
0
    }
105
106
0
    for (row, columns) in records.iter_rows().into_iter().enumerate() {
107
0
        let mut row_height = 0;
108
0
        for (col, cell) in columns.into_iter().enumerate() {
109
0
            let pos = (row, col).into();
110
0
111
0
            let width = cell.width();
112
0
            let height = cell.count_lines();
113
0
            let pad = cfg.get_padding(pos);
114
0
            let width = width + pad.left.size + pad.right.size;
115
0
            let height = height + pad.top.size + pad.bottom.size;
116
0
117
0
            widths[col] = max(widths[col], width);
118
0
            row_height = max(row_height, height);
119
0
        }
120
121
0
        heights.push(row_height);
122
    }
123
124
0
    (widths, heights)
125
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_dimensions_basic::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_dimensions_basic::<_>
126
127
0
fn build_dimensions_spanned<R>(records: R, cfg: &SpannedConfig) -> (Vec<usize>, Vec<usize>)
128
0
where
129
0
    R: Records,
130
0
    <R::Iter as IntoRecords>::Cell: Cell,
131
{
132
0
    let count_columns = records.count_columns();
133
134
0
    let mut widths = vec![0; count_columns];
135
0
    let mut heights = vec![];
136
0
    if let Some(count_rows) = records.hint_count_rows() {
137
0
        heights.reserve(count_rows);
138
0
    }
139
140
0
    let mut vspans = HashMap::new();
141
0
    let mut hspans = HashMap::new();
142
143
0
    for (row, columns) in records.iter_rows().into_iter().enumerate() {
144
0
        let mut row_height = 0;
145
0
        for (col, cell) in columns.into_iter().enumerate() {
146
0
            let pos = (row, col).into();
147
0
            if !cfg.is_cell_visible(pos) {
148
0
                continue;
149
0
            }
150
151
0
            let width = cell.width();
152
0
            let height = cell.count_lines();
153
0
            let pad = cfg.get_padding(pos);
154
0
            let width = width + pad.left.size + pad.right.size;
155
0
            let height = height + pad.top.size + pad.bottom.size;
156
157
0
            match cfg.get_column_span(pos) {
158
0
                Some(n) if n > 1 => {
159
0
                    vspans.insert(pos, (n, width));
160
0
                }
161
0
                _ => widths[col] = max(widths[col], width),
162
            }
163
164
0
            match cfg.get_row_span(pos) {
165
0
                Some(n) if n > 1 => {
166
0
                    hspans.insert(pos, (n, height));
167
0
                }
168
0
                _ => row_height = max(row_height, height),
169
            }
170
        }
171
172
0
        heights.push(row_height);
173
    }
174
175
0
    let count_rows = heights.len();
176
177
0
    adjust_vspans(cfg, count_columns, &vspans, &mut widths);
178
0
    adjust_hspans(cfg, count_rows, &hspans, &mut heights);
179
180
0
    (widths, heights)
181
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_dimensions_spanned::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_dimensions_spanned::<_>
182
183
0
fn adjust_hspans(
184
0
    cfg: &SpannedConfig,
185
0
    len: usize,
186
0
    spans: &HashMap<Position, (usize, usize)>,
187
0
    heights: &mut [usize],
188
0
) {
189
0
    if spans.is_empty() {
190
0
        return;
191
0
    }
192
193
0
    let mut spans_ordered = spans.iter().map(|(k, v)| (*k, *v)).collect::<Vec<_>>();
194
0
    spans_ordered.sort_unstable_by(|(arow, acol), (brow, bcol)| match arow.cmp(brow) {
195
0
        Ordering::Equal => acol.cmp(bcol),
196
0
        ord => ord,
197
0
    });
198
199
0
    for (pos, (span, height)) in spans_ordered {
200
0
        adjust_row_range(cfg, height, len, pos.row, pos.row + span, heights);
201
0
    }
202
0
}
203
204
0
fn adjust_row_range(
205
0
    cfg: &SpannedConfig,
206
0
    max_span_height: usize,
207
0
    len: usize,
208
0
    start: usize,
209
0
    end: usize,
210
0
    heights: &mut [usize],
211
0
) {
212
0
    let range_height = range_height(cfg, len, start, end, heights);
213
0
    if range_height >= max_span_height {
214
0
        return;
215
0
    }
216
217
0
    inc_range(heights, max_span_height - range_height, start, end);
218
0
}
219
220
0
fn range_height(
221
0
    cfg: &SpannedConfig,
222
0
    len: usize,
223
0
    start: usize,
224
0
    end: usize,
225
0
    heights: &[usize],
226
0
) -> usize {
227
0
    let count_borders = count_horizontal_borders(cfg, len, start, end);
228
0
    let range_height = heights[start..end].iter().sum::<usize>();
229
0
    count_borders + range_height
230
0
}
231
232
0
fn count_horizontal_borders(cfg: &SpannedConfig, len: usize, start: usize, end: usize) -> usize {
233
0
    (start..end)
234
0
        .skip(1)
235
0
        .filter(|&i| cfg.has_horizontal(i, len))
236
0
        .count()
237
0
}
238
239
0
fn inc_range(list: &mut [usize], size: usize, start: usize, end: usize) {
240
0
    if list.is_empty() {
241
0
        return;
242
0
    }
243
244
0
    let span = end - start;
245
0
    let one = size / span;
246
0
    let rest = size - span * one;
247
248
0
    let mut i = start;
249
0
    while i < end {
250
0
        if i == start {
251
0
            list[i] += one + rest;
252
0
        } else {
253
0
            list[i] += one;
254
0
        }
255
256
0
        i += 1;
257
    }
258
0
}
259
260
0
fn adjust_vspans(
261
0
    cfg: &SpannedConfig,
262
0
    len: usize,
263
0
    spans: &HashMap<Position, (usize, usize)>,
264
0
    widths: &mut [usize],
265
0
) {
266
0
    if spans.is_empty() {
267
0
        return;
268
0
    }
269
270
    // The overall width distribution will be different depend on the order.
271
    //
272
    // We sort spans in order to prioritize the smaller spans first.
273
0
    let mut spans_ordered = spans.iter().map(|(k, v)| (*k, *v)).collect::<Vec<_>>();
274
0
    spans_ordered.sort_unstable_by(|a, b| match a.1 .0.cmp(&b.1 .0) {
275
0
        Ordering::Equal => a.0.cmp(&b.0),
276
0
        o => o,
277
0
    });
278
279
0
    for (pos, (span, width)) in spans_ordered {
280
0
        adjust_column_range(cfg, width, len, pos.col, pos.col + span, widths);
281
0
    }
282
0
}
283
284
0
fn adjust_column_range(
285
0
    cfg: &SpannedConfig,
286
0
    max_span_width: usize,
287
0
    len: usize,
288
0
    start: usize,
289
0
    end: usize,
290
0
    widths: &mut [usize],
291
0
) {
292
0
    let range_width = range_width(cfg, len, start, end, widths);
293
0
    if range_width >= max_span_width {
294
0
        return;
295
0
    }
296
297
0
    inc_range(widths, max_span_width - range_width, start, end);
298
0
}
299
300
0
fn range_width(
301
0
    cfg: &SpannedConfig,
302
0
    len: usize,
303
0
    start: usize,
304
0
    end: usize,
305
0
    widths: &[usize],
306
0
) -> usize {
307
0
    let count_borders = count_vertical_borders(cfg, len, start, end);
308
0
    let range_width = widths[start..end].iter().sum::<usize>();
309
0
    count_borders + range_width
310
0
}
311
312
0
fn count_vertical_borders(cfg: &SpannedConfig, len: usize, start: usize, end: usize) -> usize {
313
0
    (start..end)
314
0
        .skip(1)
315
0
        .filter(|&i| cfg.has_vertical(i, len))
316
0
        .count()
317
0
}
318
319
0
fn build_height<R>(records: R, cfg: &SpannedConfig) -> Vec<usize>
320
0
where
321
0
    R: Records,
322
0
    <R::Iter as IntoRecords>::Cell: Cell,
323
{
324
0
    if cfg.has_column_spans() || cfg.has_row_spans() {
325
0
        build_height_spanned(records, cfg)
326
    } else {
327
0
        build_height_basic(records, cfg)
328
    }
329
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_height::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_height::<_>
330
331
0
fn build_height_basic<R>(records: R, cfg: &SpannedConfig) -> Vec<usize>
332
0
where
333
0
    R: Records,
334
0
    <R::Iter as IntoRecords>::Cell: Cell,
335
{
336
0
    let mut heights = vec![];
337
0
    if let Some(count_rows) = records.hint_count_rows() {
338
0
        heights.reserve(count_rows);
339
0
    }
340
341
0
    for (row, columns) in records.iter_rows().into_iter().enumerate() {
342
0
        let mut row_height = 0;
343
0
        for (col, cell) in columns.into_iter().enumerate() {
344
0
            let pos = (row, col).into();
345
0
            let pad = cfg.get_padding(pos);
346
0
            let height = cell.count_lines() + pad.bottom.size + pad.top.size;
347
0
            row_height = max(row_height, height);
348
0
        }
349
350
0
        heights.push(row_height);
351
    }
352
353
0
    heights
354
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_height_basic::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_height_basic::<_>
355
356
0
fn build_height_spanned<R>(records: R, cfg: &SpannedConfig) -> Vec<usize>
357
0
where
358
0
    R: Records,
359
0
    <R::Iter as IntoRecords>::Cell: Cell,
360
{
361
0
    let mut hspans = HashMap::new();
362
0
    let mut heights = vec![];
363
0
    if let Some(count_rows) = records.hint_count_rows() {
364
0
        heights.reserve(count_rows);
365
0
    }
366
367
0
    for (row, columns) in records.iter_rows().into_iter().enumerate() {
368
0
        let mut row_height = 0;
369
0
        for (col, cell) in columns.into_iter().enumerate() {
370
0
            let pos = (row, col).into();
371
0
            if !cfg.is_cell_visible(pos) {
372
0
                continue;
373
0
            }
374
375
0
            let pad = cfg.get_padding(pos);
376
0
            let height = cell.count_lines() + pad.bottom.size + pad.top.size;
377
0
            match cfg.get_row_span(pos) {
378
0
                Some(n) if n > 1 => {
379
0
                    hspans.insert(pos, (n, height));
380
0
                }
381
0
                _ => row_height = max(row_height, height),
382
            }
383
        }
384
385
0
        heights.push(row_height);
386
    }
387
388
0
    adjust_hspans(cfg, heights.len(), &hspans, &mut heights);
389
390
0
    heights
391
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_height_spanned::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_height_spanned::<_>
392
393
0
fn build_width<R>(records: R, cfg: &SpannedConfig) -> Vec<usize>
394
0
where
395
0
    R: Records,
396
0
    <R::Iter as IntoRecords>::Cell: Cell,
397
{
398
0
    if cfg.has_column_spans() || cfg.has_row_spans() {
399
0
        build_width_spanned(records, cfg)
400
    } else {
401
0
        build_width_basic(records, cfg)
402
    }
403
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_width::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_width::<_>
404
405
0
fn build_width_basic<R>(records: R, cfg: &SpannedConfig) -> Vec<usize>
406
0
where
407
0
    R: Records,
408
0
    <R::Iter as IntoRecords>::Cell: Cell,
409
{
410
0
    let count_columns = records.count_columns();
411
0
    let mut widths = vec![0; count_columns];
412
413
0
    for (row, columns) in records.iter_rows().into_iter().enumerate() {
414
0
        for (col, cell) in columns.into_iter().enumerate() {
415
0
            let pos = (row, col).into();
416
0
            let pad = cfg.get_padding(pos);
417
0
            let width = cell.width() + pad.left.size + pad.right.size;
418
0
            widths[col] = max(widths[col], width);
419
0
        }
420
    }
421
422
0
    widths
423
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_width_basic::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_width_basic::<_>
424
425
0
fn build_width_spanned<R>(records: R, cfg: &SpannedConfig) -> Vec<usize>
426
0
where
427
0
    R: Records,
428
0
    <R::Iter as IntoRecords>::Cell: Cell,
429
{
430
0
    let count_columns = records.count_columns();
431
432
0
    let mut widths = vec![0; count_columns];
433
0
    let mut vspans = HashMap::new();
434
435
0
    for (row, columns) in records.iter_rows().into_iter().enumerate() {
436
0
        for (col, cell) in columns.into_iter().enumerate() {
437
0
            let pos = (row, col).into();
438
0
            if !cfg.is_cell_visible(pos) {
439
0
                continue;
440
0
            }
441
442
0
            let pad = cfg.get_padding(pos);
443
0
            let width = cell.width() + pad.left.size + pad.right.size;
444
0
            match cfg.get_column_span(pos) {
445
0
                Some(n) if n > 1 => {
446
0
                    vspans.insert(pos, (n, width));
447
0
                }
448
0
                _ => widths[col] = max(widths[col], width),
449
            }
450
        }
451
    }
452
453
0
    adjust_vspans(cfg, count_columns, &vspans, &mut widths);
454
455
0
    widths
456
0
}
Unexecuted instantiation: papergrid::dimension::peekable::build_width_spanned::<&papergrid::records::vec_records::VecRecords<papergrid::records::vec_records::text::Text<alloc::string::String>>>
Unexecuted instantiation: papergrid::dimension::peekable::build_width_spanned::<_>