1use serde::{Deserialize, Serialize};
2use std::ops::{Add, Sub};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
8pub struct Rect {
9 pub x: u16,
10 pub y: u16,
11 pub width: u16,
12 pub height: u16,
13}
14
15impl Rect {
16 pub const ZERO: Rect = Rect {
17 x: 0,
18 y: 0,
19 width: 0,
20 height: 0,
21 };
22
23 pub const fn new(x: u16, y: u16, width: u16, height: u16) -> Self {
24 Self {
25 x,
26 y,
27 width,
28 height,
29 }
30 }
31
32 pub const fn area(&self) -> u32 {
34 self.width as u32 * self.height as u32
35 }
36
37 pub const fn is_empty(&self) -> bool {
39 self.width == 0 || self.height == 0
40 }
41
42 pub const fn left(&self) -> u16 {
44 self.x
45 }
46
47 pub const fn right(&self) -> u16 {
49 self.x.saturating_add(self.width)
50 }
51
52 pub const fn top(&self) -> u16 {
54 self.y
55 }
56
57 pub const fn bottom(&self) -> u16 {
59 self.y.saturating_add(self.height)
60 }
61
62 pub const fn center(&self) -> Position {
64 Position {
65 x: self.x.saturating_add(self.width / 2),
66 y: self.y.saturating_add(self.height / 2),
67 }
68 }
69
70 pub fn intersection(&self, other: Rect) -> Rect {
72 let x = self.x.max(other.x);
73 let y = self.y.max(other.y);
74 let right = self.right().min(other.right());
75 let bottom = self.bottom().min(other.bottom());
76 Rect {
77 x,
78 y,
79 width: right.saturating_sub(x),
80 height: bottom.saturating_sub(y),
81 }
82 }
83
84 pub fn union(&self, other: Rect) -> Rect {
86 let x = self.x.min(other.x);
87 let y = self.y.min(other.y);
88 let right = self.right().max(other.right());
89 let bottom = self.bottom().max(other.bottom());
90 Rect {
91 x,
92 y,
93 width: right.saturating_sub(x),
94 height: bottom.saturating_sub(y),
95 }
96 }
97
98 pub fn contains(&self, pos: Position) -> bool {
100 pos.x >= self.x && pos.x < self.right() && pos.y >= self.y && pos.y < self.bottom()
101 }
102
103 pub fn inner(&self, margin: Margin) -> Rect {
105 let x = self.x.saturating_add(margin.left);
106 let y = self.y.saturating_add(margin.top);
107 let width = self
108 .width
109 .saturating_sub(margin.left.saturating_add(margin.right));
110 let height = self
111 .height
112 .saturating_sub(margin.top.saturating_add(margin.bottom));
113 Rect {
114 x,
115 y,
116 width,
117 height,
118 }
119 }
120
121 pub fn positions(&self) -> impl Iterator<Item = Position> + '_ {
123 (self.y..self.bottom())
124 .flat_map(move |y| (self.x..self.right()).map(move |x| Position { x, y }))
125 }
126
127 pub fn rows(&self) -> impl Iterator<Item = u16> {
129 self.y..self.bottom()
130 }
131
132 pub fn columns(&self) -> impl Iterator<Item = u16> {
134 self.x..self.right()
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
140pub struct Position {
141 pub x: u16,
142 pub y: u16,
143}
144
145impl Position {
146 pub const fn new(x: u16, y: u16) -> Self {
147 Self { x, y }
148 }
149}
150
151impl Add<Offset> for Position {
152 type Output = Position;
153 fn add(self, rhs: Offset) -> Self::Output {
154 Position {
155 x: (self.x as i32 + rhs.x as i32).max(0) as u16,
156 y: (self.y as i32 + rhs.y as i32).max(0) as u16,
157 }
158 }
159}
160
161impl Sub for Position {
162 type Output = Offset;
163 fn sub(self, rhs: Self) -> Self::Output {
164 Offset {
165 x: self.x as i16 - rhs.x as i16,
166 y: self.y as i16 - rhs.y as i16,
167 }
168 }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
173pub struct Offset {
174 pub x: i16,
175 pub y: i16,
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
180pub struct Margin {
181 pub top: u16,
182 pub right: u16,
183 pub bottom: u16,
184 pub left: u16,
185}
186
187impl Margin {
188 pub const ZERO: Margin = Margin {
189 top: 0,
190 right: 0,
191 bottom: 0,
192 left: 0,
193 };
194
195 pub const fn uniform(value: u16) -> Self {
197 Self {
198 top: value,
199 right: value,
200 bottom: value,
201 left: value,
202 }
203 }
204
205 pub const fn symmetric(vertical: u16, horizontal: u16) -> Self {
207 Self {
208 top: vertical,
209 right: horizontal,
210 bottom: vertical,
211 left: horizontal,
212 }
213 }
214
215 pub const fn new(top: u16, right: u16, bottom: u16, left: u16) -> Self {
217 Self {
218 top,
219 right,
220 bottom,
221 left,
222 }
223 }
224}
225
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
228pub struct Size {
229 pub width: u16,
230 pub height: u16,
231}
232
233impl Size {
234 pub const fn new(width: u16, height: u16) -> Self {
235 Self { width, height }
236 }
237}
238
239impl From<Rect> for Size {
240 fn from(rect: Rect) -> Self {
241 Size {
242 width: rect.width,
243 height: rect.height,
244 }
245 }
246}