display_types/screen.rs
1/// Physical screen dimensions or aspect ratio, decoded from EDID base block bytes `0x15`–`0x16`.
2///
3/// The two bytes encode one of three things depending on which are zero:
4///
5/// | `0x15` | `0x16` | Meaning |
6/// |--------|--------|-----------------------------------|
7/// | non-0 | non-0 | Physical width × height in cm |
8/// | non-0 | 0 | Landscape aspect ratio |
9/// | 0 | non-0 | Portrait aspect ratio |
10/// | 0 | 0 | Undefined — `None` on the field |
11#[non_exhaustive]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ScreenSize {
15 /// Physical screen dimensions. Values are in centimetres (1–255 cm per axis).
16 Physical {
17 /// Horizontal screen size in centimetres.
18 width_cm: u8,
19 /// Vertical screen size in centimetres.
20 height_cm: u8,
21 },
22 /// Landscape aspect ratio (width ÷ height > 1), encoded as a raw EDID byte.
23 ///
24 /// Call [`landscape_ratio`][Self::landscape_ratio] for the computed `f32` value.
25 Landscape(u8),
26 /// Portrait aspect ratio (width ÷ height < 1), encoded as a raw EDID byte.
27 ///
28 /// Call [`portrait_ratio`][Self::portrait_ratio] for the computed `f32` value.
29 Portrait(u8),
30}
31
32impl ScreenSize {
33 /// Returns the landscape aspect ratio (width ÷ height) for a `Landscape` variant.
34 ///
35 /// Formula: `(raw + 99) / 100`. Range: 1.00 → 3.54.
36 /// Returns `None` for other variants.
37 pub fn landscape_ratio(&self) -> Option<f32> {
38 if let Self::Landscape(v) = self {
39 Some((*v as f32 + 99.0) / 100.0)
40 } else {
41 None
42 }
43 }
44
45 /// Returns the portrait aspect ratio (width ÷ height) for a `Portrait` variant.
46 ///
47 /// Formula: `100 / (raw + 99)`. Range: 0.28 → 0.99.
48 /// Returns `None` for other variants.
49 pub fn portrait_ratio(&self) -> Option<f32> {
50 if let Self::Portrait(v) = self {
51 Some(100.0 / (*v as f32 + 99.0))
52 } else {
53 None
54 }
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn landscape_ratio_correct_formula() {
64 // raw=1: (1 + 99) / 100 = 1.00
65 assert_eq!(ScreenSize::Landscape(1).landscape_ratio(), Some(1.00));
66 // raw=100: (100 + 99) / 100 = 1.99
67 assert!((ScreenSize::Landscape(100).landscape_ratio().unwrap() - 1.99).abs() < 1e-5);
68 }
69
70 #[test]
71 fn landscape_ratio_none_for_other_variants() {
72 assert_eq!(
73 ScreenSize::Physical {
74 width_cm: 60,
75 height_cm: 34
76 }
77 .landscape_ratio(),
78 None
79 );
80 assert_eq!(ScreenSize::Portrait(1).landscape_ratio(), None);
81 }
82
83 #[test]
84 fn portrait_ratio_correct_formula() {
85 // raw=1: 100 / (1 + 99) = 1.00
86 assert_eq!(ScreenSize::Portrait(1).portrait_ratio(), Some(1.00));
87 // raw=100: 100 / (100 + 99) = 100 / 199 ≈ 0.50251
88 let r = ScreenSize::Portrait(100).portrait_ratio().unwrap();
89 assert!((r - 100.0 / 199.0).abs() < 1e-5);
90 }
91
92 #[test]
93 fn portrait_ratio_none_for_other_variants() {
94 assert_eq!(
95 ScreenSize::Physical {
96 width_cm: 60,
97 height_cm: 34
98 }
99 .portrait_ratio(),
100 None
101 );
102 assert_eq!(ScreenSize::Landscape(1).portrait_ratio(), None);
103 }
104}