ironrdp_pdu/
geometry.rs

1use core::cmp::{max, min};
2
3use ironrdp_core::{ensure_fixed_part_size, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor};
4
5pub(crate) mod private {
6    pub struct BaseRectangle {
7        pub left: u16,
8        pub top: u16,
9        pub right: u16,
10        pub bottom: u16,
11    }
12
13    impl BaseRectangle {
14        pub fn empty() -> Self {
15            Self {
16                left: 0,
17                top: 0,
18                right: 0,
19                bottom: 0,
20            }
21        }
22    }
23
24    pub trait RectangleImpl: Sized {
25        fn from_base(rect: BaseRectangle) -> Self;
26        fn to_base(&self) -> BaseRectangle;
27
28        fn left(&self) -> u16;
29        fn top(&self) -> u16;
30        fn right(&self) -> u16;
31        fn bottom(&self) -> u16;
32    }
33}
34
35use private::{BaseRectangle, RectangleImpl};
36
37pub trait Rectangle: RectangleImpl {
38    fn width(&self) -> u16;
39    fn height(&self) -> u16;
40
41    fn empty() -> Self {
42        Self::from_base(BaseRectangle::empty())
43    }
44
45    fn union_all(rectangles: &[Self]) -> Self {
46        Self::from_base(BaseRectangle {
47            left: rectangles.iter().map(|r| r.left()).min().unwrap_or(0),
48            top: rectangles.iter().map(|r| r.top()).min().unwrap_or(0),
49            right: rectangles.iter().map(|r| r.right()).max().unwrap_or(0),
50            bottom: rectangles.iter().map(|r| r.bottom()).max().unwrap_or(0),
51        })
52    }
53
54    fn intersect(&self, other: &Self) -> Option<Self> {
55        let a = self.to_base();
56        let b = other.to_base();
57
58        let result = BaseRectangle {
59            left: max(a.left, b.left),
60            top: max(a.top, b.top),
61            right: min(a.right, b.right),
62            bottom: min(a.bottom, b.bottom),
63        };
64
65        if result.left <= result.right && result.top <= result.bottom {
66            Some(Self::from_base(result))
67        } else {
68            None
69        }
70    }
71
72    #[must_use]
73    fn union(&self, other: &Self) -> Self {
74        let a = self.to_base();
75        let b = other.to_base();
76
77        let result = BaseRectangle {
78            left: min(a.left, b.left),
79            top: min(a.top, b.top),
80            right: max(a.right, b.right),
81            bottom: max(a.bottom, b.bottom),
82        };
83
84        Self::from_base(result)
85    }
86}
87
88/// An **inclusive** rectangle.
89///
90/// This struct is defined as an **inclusive** rectangle.
91/// That is, the pixel at coordinate (right, bottom) is included in the rectangle.
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct InclusiveRectangle {
94    pub left: u16,
95    pub top: u16,
96    pub right: u16,
97    pub bottom: u16,
98}
99
100/// An **exclusive** rectangle.
101/// This struct is defined as an **exclusive** rectangle.
102/// That is, the pixel at coordinate (right, bottom) is not included in the rectangle.
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct ExclusiveRectangle {
105    pub left: u16,
106    pub top: u16,
107    pub right: u16,
108    pub bottom: u16,
109}
110
111macro_rules! impl_rectangle {
112    ($type:ty) => {
113        impl RectangleImpl for $type {
114            fn from_base(rect: BaseRectangle) -> Self {
115                Self {
116                    left: rect.left,
117                    top: rect.top,
118                    right: rect.right,
119                    bottom: rect.bottom,
120                }
121            }
122
123            fn to_base(&self) -> BaseRectangle {
124                BaseRectangle {
125                    left: self.left,
126                    top: self.top,
127                    right: self.right,
128                    bottom: self.bottom,
129                }
130            }
131
132            fn left(&self) -> u16 {
133                self.left
134            }
135            fn top(&self) -> u16 {
136                self.top
137            }
138            fn right(&self) -> u16 {
139                self.right
140            }
141            fn bottom(&self) -> u16 {
142                self.bottom
143            }
144        }
145    };
146}
147
148impl_rectangle!(InclusiveRectangle);
149impl_rectangle!(ExclusiveRectangle);
150
151impl Rectangle for InclusiveRectangle {
152    fn width(&self) -> u16 {
153        self.right - self.left + 1
154    }
155
156    fn height(&self) -> u16 {
157        self.bottom - self.top + 1
158    }
159}
160
161impl Rectangle for ExclusiveRectangle {
162    fn width(&self) -> u16 {
163        self.right - self.left
164    }
165
166    fn height(&self) -> u16 {
167        self.bottom - self.top
168    }
169}
170
171impl InclusiveRectangle {
172    const NAME: &'static str = "InclusiveRectangle";
173
174    pub const FIXED_PART_SIZE: usize = 2 /* left */ + 2 /* top */ + 2 /* right */ + 2 /* bottom */;
175
176    pub const ENCODED_SIZE: usize = Self::FIXED_PART_SIZE;
177}
178
179impl Encode for InclusiveRectangle {
180    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
181        ensure_fixed_part_size!(in: dst);
182
183        dst.write_u16(self.left);
184        dst.write_u16(self.top);
185        dst.write_u16(self.right);
186        dst.write_u16(self.bottom);
187
188        Ok(())
189    }
190
191    fn name(&self) -> &'static str {
192        Self::NAME
193    }
194
195    fn size(&self) -> usize {
196        Self::FIXED_PART_SIZE
197    }
198}
199
200impl<'de> Decode<'de> for InclusiveRectangle {
201    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
202        ensure_fixed_part_size!(in: src);
203
204        let left = src.read_u16();
205        let top = src.read_u16();
206        let right = src.read_u16();
207        let bottom = src.read_u16();
208
209        Ok(Self {
210            left,
211            top,
212            right,
213            bottom,
214        })
215    }
216}
217
218impl ExclusiveRectangle {
219    const NAME: &'static str = "ExclusiveRectangle";
220    const FIXED_PART_SIZE: usize = 2 /* left */ + 2 /* top */ + 2 /* right */ + 2 /* bottom */;
221
222    pub const ENCODED_SIZE: usize = Self::FIXED_PART_SIZE;
223}
224
225impl Encode for ExclusiveRectangle {
226    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
227        ensure_fixed_part_size!(in: dst);
228
229        dst.write_u16(self.left);
230        dst.write_u16(self.top);
231        dst.write_u16(self.right);
232        dst.write_u16(self.bottom);
233
234        Ok(())
235    }
236
237    fn name(&self) -> &'static str {
238        Self::NAME
239    }
240
241    fn size(&self) -> usize {
242        Self::FIXED_PART_SIZE
243    }
244}
245
246impl<'de> Decode<'de> for ExclusiveRectangle {
247    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
248        ensure_fixed_part_size!(in: src);
249
250        let left = src.read_u16();
251        let top = src.read_u16();
252        let right = src.read_u16();
253        let bottom = src.read_u16();
254
255        Ok(Self {
256            left,
257            top,
258            right,
259            bottom,
260        })
261    }
262}