ailloli_ui_terminal_core/size.rs
1//! Terminal grid dimensions in rows and columns.
2
3use serde::{Deserialize, Serialize};
4
5/// Terminal grid dimensions, measured in whole character cells.
6///
7/// [`Self::new`] guarantees both values are at least one. Public fields and
8/// derived deserialization can bypass that invariant; use [`Self::clamped`]
9/// before arithmetic/indexing. There is no upper bound.
10///
11/// # Examples
12///
13/// ```
14/// use ailloli_ui_terminal_core::TerminalSize;
15/// assert_eq!(TerminalSize::new(24, 80), TerminalSize { rows: 24, cols: 80 });
16/// ```
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18pub struct TerminalSize {
19 /// Visible row count in cells.
20 pub rows: usize,
21 /// Visible column count in cells.
22 pub cols: usize,
23}
24
25impl TerminalSize {
26 /// Default terminal height: 24 rows.
27 ///
28 /// # Examples
29 ///
30 /// ```
31 /// use ailloli_ui_terminal_core::TerminalSize;
32 /// assert_eq!(TerminalSize::DEFAULT_ROWS, 24);
33 /// ```
34 pub const DEFAULT_ROWS: usize = 24;
35 /// Default terminal width: 80 columns.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// use ailloli_ui_terminal_core::TerminalSize;
41 /// assert_eq!(TerminalSize::DEFAULT_COLS, 80);
42 /// ```
43 pub const DEFAULT_COLS: usize = 80;
44
45 /// Creates a size, replacing each zero dimension independently with one.
46 ///
47 /// All positive `usize` values, including [`usize::MAX`], are retained.
48 ///
49 /// # Examples
50 ///
51 /// ```
52 /// use ailloli_ui_terminal_core::TerminalSize;
53 /// assert_eq!(TerminalSize::new(0, 0), TerminalSize { rows: 1, cols: 1 });
54 /// ```
55 pub const fn new(rows: usize, cols: usize) -> Self {
56 Self {
57 rows: if rows == 0 { 1 } else { rows },
58 cols: if cols == 0 { 1 } else { cols },
59 }
60 }
61
62 /// Returns this size with zero dimensions replaced by one.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// use ailloli_ui_terminal_core::TerminalSize;
68 /// assert_eq!(TerminalSize { rows: 0, cols: 7 }.clamped(), TerminalSize::new(1, 7));
69 /// ```
70 pub const fn clamped(self) -> Self {
71 Self::new(self.rows, self.cols)
72 }
73}
74
75impl Default for TerminalSize {
76 fn default() -> Self {
77 Self::new(Self::DEFAULT_ROWS, Self::DEFAULT_COLS)
78 }
79}