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#[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#[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 + 2 + 2 + 2 ;
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 + 2 + 2 + 2 ;
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}