muxr_core/protocol/
terminal.rs1use std::num::NonZeroU16;
2
3use rootcause::report;
4use serde::Deserialize;
5use serde::Serialize;
6
7#[derive(rkyv::Archive, Clone, Debug, Deserialize, rkyv::Deserialize, Eq, PartialEq, Serialize, rkyv::Serialize)]
8pub struct TerminalSize {
9 cols: NonZeroU16,
10 rows: NonZeroU16,
11}
12
13impl TerminalSize {
14 pub fn new(cols: u16, rows: u16) -> rootcause::Result<Self> {
19 let Some(cols) = NonZeroU16::new(cols) else {
20 return Err(report!("invalid muxr terminal size").attach("cols=0"));
21 };
22 let Some(rows) = NonZeroU16::new(rows) else {
23 return Err(report!("invalid muxr terminal size").attach("rows=0"));
24 };
25
26 Ok(Self { cols, rows })
27 }
28
29 #[must_use]
31 pub const fn cols(&self) -> u16 {
32 self.cols.get()
33 }
34
35 #[must_use]
37 pub const fn rows(&self) -> u16 {
38 self.rows.get()
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use rstest::rstest;
45 use test_that::prelude::*;
46
47 use super::*;
48
49 #[rstest]
50 #[case::zero_cols(r#"{"cols":0,"rows":24}"#)]
51 #[case::zero_rows(r#"{"cols":80,"rows":0}"#)]
52 fn test_terminal_size_deserialize_when_dimension_is_zero_returns_error(#[case] raw: &str) {
53 assert_that!(serde_json::from_str::<TerminalSize>(raw), err(anything()));
54 }
55
56 #[rstest]
57 #[case::zero_cols(0, 24)]
58 #[case::zero_rows(80, 0)]
59 fn test_terminal_size_new_when_dimension_is_zero_returns_error(#[case] cols: u16, #[case] rows: u16) {
60 assert_that!(TerminalSize::new(cols, rows), err(anything()));
61 }
62
63 #[test]
64 fn test_terminal_size_new_when_dimensions_are_nonzero_returns_size() -> rootcause::Result<()> {
65 let size = TerminalSize::new(120, 40)?;
66
67 assert_that!(size.cols(), eq(120));
68 assert_that!(size.rows(), eq(40));
69 Ok(())
70 }
71}