1#![feature(iter_advance_by)]
2#![feature(stmt_expr_attributes)]
3#![feature(trusted_len)]
4
5#![deny(warnings)]
6#![allow(unstable_name_collisions)] #![doc(test(attr(deny(warnings))))]
8#![doc(test(attr(allow(dead_code))))]
9#![doc(test(attr(allow(unused_variables))))]
10#![allow(clippy::collapsible_else_if)]
11#![allow(clippy::collapsible_if)]
12#![allow(clippy::manual_map)]
13#![allow(clippy::many_single_char_names)]
14#![allow(clippy::too_many_arguments)]
15
16#![no_std]
17
18use core::cmp::{min, max};
19use core::iter::{FusedIterator, TrustedLen};
20use core::num::{NonZeroI16, NonZeroUsize};
21use core::ops::{Add, AddAssign, Sub, SubAssign, Neg, Index, IndexMut};
22use either::{Either, Left, Right};
23use enum_derive_2018::{EnumDisplay, EnumFromStr};
24use macro_attr_2018::macro_attr;
25use num_traits::Zero;
26#[cfg(test)]
27use quickcheck::{Arbitrary, Gen};
28#[cfg(feature="serde")]
29use serde::{Serialize, Deserialize, Deserializer};
30#[cfg(feature="serde")]
31use serde::de::Unexpected;
32#[cfg(feature="serde")]
33use serde::de::Error as de_Error;
34
35#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
36pub struct Range1d {
37 pub start: i16,
38 pub end: i16,
39}
40
41impl Range1d {
42 pub fn new(start: i16, end: i16) -> Self {
43 Range1d { start, end }
44 }
45
46 pub fn len(self) -> u16 { self.end.wrapping_sub(self.start) as u16 }
47
48 pub fn inclusive(start: i16, end: i16) -> Option<Self> {
49 let res = Range1d { start, end: end.wrapping_add(1) };
50 if res.is_empty() { None } else { Some(res) }
51 }
52
53 pub fn contains(self, coord: i16) -> bool {
54 (coord.wrapping_sub(self.start) as u16) < (self.end.wrapping_sub(self.start) as u16)
55 }
56
57 pub fn is_empty(self) -> bool {
58 self.start == self.end
59 }
60
61 pub fn intersect(self, other: Range1d) -> Range1d {
62 let (long, short) = if self.len() <= other.len() {
63 (other, self)
64 } else {
65 (self, other)
66 };
67 if long.contains(short.start) {
68 if long.contains(short.end) {
69 short
70 } else {
71 Range1d::new(short.start, long.end)
72 }
73 } else {
74 if long.contains(short.end) {
75 Range1d::new(long.start, short.end)
76 } else {
77 Range1d::new(self.start, self.start)
78 }
79 }
80 }
81
82 pub fn union(self, other: Range1d) -> Option<Range1d> {
83 let (long, short) = if self.len() <= other.len() {
84 (other, self)
85 } else {
86 (self, other)
87 };
88 if long.contains(short.start) {
89 if long.contains(short.end) {
90 if Range1d::new(long.start, short.end).len() >= Range1d::new(long.start, short.start).len() {
91 Some(long)
92 } else {
93 None
94 }
95 } else {
96 let res = Range1d::new(long.start, short.end);
97 if res.is_empty() { None } else { Some(res) }
98 }
99 } else {
100 if long.contains(short.end) {
101 let res = Range1d::new(short.start, long.end);
102 if res.is_empty() { None } else { Some(res) }
103 } else {
104 if other.is_empty() {
105 Some(self)
106 } else if self.is_empty() {
107 Some(other)
108 } else {
109 let u = Range1d::new(self.start, other.end);
110 let v = Range1d::new(other.start, self.end);
111 if u.is_empty() {
112 if v.is_empty() { None } else { Some(v) }
113 } else {
114 Some(if v.is_empty() {
115 u
116 } else {
117 if u.len() < v.len() { u } else { v }
118 })
119 }
120 }
121 }
122 }
123 }
124}
125
126impl Iterator for Range1d {
127 type Item = i16;
128
129 fn next(&mut self) -> Option<i16> {
130 if !self.is_empty() {
131 let item = self.start;
132 self.start = self.start.wrapping_add(1);
133 Some(item)
134 } else {
135 None
136 }
137 }
138
139 fn size_hint(&self) -> (usize, Option<usize>) {
140 let len = self.len();
141 (len, Some(len))
142 }
143
144 fn count(self) -> usize { self.len() as usize }
145
146 fn last(self) -> Option<i16> {
147 if self.is_empty() { None } else { Some(self.end) }
148 }
149
150 fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
151 if let Some(rem) = n.checked_sub(self.len()).and_then(NonZeroUsize::new) {
152 self.start = self.end;
153 return Err(rem);
154 }
155 self.start = self.start.wrapping_add(n as u16 as i16);
156 Ok(())
157 }
158}
159
160impl FusedIterator for Range1d { }
161
162impl DoubleEndedIterator for Range1d {
163 fn next_back(&mut self) -> Option<i16> {
164 if !self.is_empty() {
165 let item = self.end;
166 self.end = self.end.wrapping_sub(1);
167 Some(item)
168 } else {
169 None
170 }
171 }
172
173 fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
174 if let Some(rem) = n.checked_sub(self.len()).and_then(NonZeroUsize::new) {
175 self.end = self.start;
176 return Err(rem);
177 }
178 self.end = self.end.wrapping_sub(n as u16 as i16);
179 Ok(())
180 }
181}
182
183impl ExactSizeIterator for Range1d {
184 fn len(&self) -> usize {
185 Range1d::len(*self) as usize
186 }
187}
188
189unsafe impl TrustedLen for Range1d { }
190
191macro_attr! {
192 #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
193 #[derive(Eq, PartialEq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
194 #[derive(EnumDisplay!, EnumFromStr!)]
195 pub enum Side {
196 Left,
197 Top,
198 Right,
199 Bottom
200 }
201}
202
203#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
204#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
205pub struct Point {
206 pub x: i16,
207 pub y: i16,
208}
209
210impl Point {
211 pub fn offset(self, d: Vector) -> Point {
212 Point { x: self.x.wrapping_add(d.x), y: self.y.wrapping_add(d.y) }
213 }
214
215 pub fn offset_from(self, other: Point) -> Vector {
216 Vector { x: self.x.wrapping_sub(other.x), y: self.y.wrapping_sub(other.y) }
217 }
218
219 pub fn relative_to(self, base: Point) -> Point {
220 Point { x: self.x.wrapping_sub(base.x), y: self.y.wrapping_sub(base.y) }
221 }
222
223 pub fn absolute_with(self, base: Point) -> Point {
224 Point { x: self.x.wrapping_add(base.x), y: self.y.wrapping_add(base.y) }
225 }
226}
227
228#[cfg(test)]
229impl Arbitrary for Point {
230 fn arbitrary(g: &mut Gen) -> Self {
231 let a = <(_, _)>::arbitrary(g);
232 Point { x: a.0, y: a.1 }
233 }
234}
235
236#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
237#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
238pub struct Vector {
239 pub x: i16,
240 pub y: i16,
241}
242
243impl Vector {
244 pub const fn null() -> Vector { Vector { x: 0, y: 0 } }
245
246 pub fn is_null(self) -> bool { self.x == 0 && self.y == 0 }
247
248 pub fn rect_area(self) -> u32 { (self.x as u16 as u32) * (self.y as u16 as u32) }
249
250 pub fn max(self, other: Vector) -> Vector {
251 Vector {
252 x: max(self.x as u16, other.x as u16) as i16,
253 y: max(self.y as u16, other.y as u16) as i16,
254 }
255 }
256
257 pub fn min(self, other: Vector) -> Vector {
258 Vector {
259 x: min(self.x as u16, other.x as u16) as i16,
260 y: min(self.y as u16, other.y as u16) as i16,
261 }
262 }
263}
264
265impl Default for Vector {
266 fn default() -> Self { Vector::null() }
267}
268
269impl Zero for Vector {
270 fn zero() -> Self { Vector::null() }
271
272 fn is_zero(&self) -> bool { self.is_null() }
273
274 fn set_zero(&mut self) { *self = Vector::null() }
275}
276
277impl Add for Vector {
278 type Output = Self;
279
280 fn add(self, other: Self) -> Self {
281 Vector { x: self.x.wrapping_add(other.x), y: self.y.wrapping_add(other.y) }
282 }
283}
284
285impl AddAssign for Vector {
286 fn add_assign(&mut self, other: Self) {
287 *self = *self + other;
288 }
289}
290
291impl Sub for Vector {
292 type Output = Self;
293
294 fn sub(self, other: Self) -> Self {
295 Vector { x: self.x.wrapping_sub(other.x), y: self.y.wrapping_sub(other.y) }
296 }
297}
298
299impl SubAssign for Vector {
300 fn sub_assign(&mut self, other: Self) {
301 *self = *self - other;
302 }
303}
304
305impl Neg for Vector {
306 type Output = Self;
307
308 fn neg(self) -> Self {
309 Vector::null() - self
310 }
311}
312
313#[cfg(test)]
314impl Arbitrary for Vector {
315 fn arbitrary(g: &mut Gen) -> Self {
316 let a = <(_, _)>::arbitrary(g);
317 Vector { x: a.0, y: a.1 }
318 }
319}
320
321#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
322#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
323pub struct VBand {
324 pub l: i16,
325 pub w: NonZeroI16,
326}
327
328impl VBand {
329 pub fn from_l_r(l: i16, r: i16) -> Option<VBand> {
330 NonZeroI16::new(r.wrapping_sub(l)).map(|w| VBand { l, w })
331 }
332
333 pub fn from_h_range(h_range: Range1d) -> Option<VBand> {
334 VBand::from_l_r(h_range.start, h_range.end)
335 }
336
337 pub fn r(self) -> i16 { self.l.wrapping_add(self.w.get()) }
338
339 pub fn h_range(self) -> Range1d { Range1d::new(self.l, self.r()) }
340
341 pub fn offset(self, d: Vector) -> VBand {
342 VBand { l: self.l.wrapping_add(d.x), w: self.w }
343 }
344
345 pub fn relative_to(self, base: Point) -> VBand {
346 VBand { l: self.l.wrapping_sub(base.x), w: self.w }
347 }
348
349 pub fn absolute_with(self, base: Point) -> VBand {
350 VBand { l: self.l.wrapping_add(base.x), w: self.w }
351 }
352}
353
354#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
355#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
356pub struct HBand {
357 pub t: i16,
358 pub h: NonZeroI16,
359}
360
361impl HBand {
362 pub fn from_t_b(t: i16, b: i16) -> Option<HBand> {
363 NonZeroI16::new(b.wrapping_sub(t)).map(|h| HBand { t, h })
364 }
365
366 pub fn from_v_range(v_range: Range1d) -> Option<HBand> {
367 HBand::from_t_b(v_range.start, v_range.end)
368 }
369
370 pub fn b(self) -> i16 { self.t.wrapping_add(self.h.get()) }
371
372 pub fn v_range(self) -> Range1d { Range1d::new(self.t, self.b()) }
373
374 pub fn offset(self, d: Vector) -> HBand {
375 HBand { t: self.t.wrapping_add(d.y), h: self.h }
376 }
377
378 pub fn relative_to(self, base: Point) -> HBand {
379 HBand { t: self.t.wrapping_sub(base.y), h: self.h }
380 }
381
382 pub fn absolute_with(self, base: Point) -> HBand {
383 HBand { t: self.t.wrapping_add(base.y), h: self.h }
384 }
385}
386
387#[cfg(feature="serde")]
388fn deserialize_thickness_value<'de, D>(d: D) -> Result<i32, D::Error> where D: Deserializer<'de> {
389 let value = i32::deserialize(d)?;
390 if value >= -(u16::MAX as u32 as i32) && value <= u16::MAX as u32 as i32 { return Ok(value); }
391 Err(D::Error::invalid_value(
392 Unexpected::Signed(value.into()),
393 &"integer in the -(2¹⁶ - 1) ..= (2¹⁶ - 1) range"
394 ))
395}
396
397#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
398#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy, Default)]
399pub struct Thickness {
400 #[cfg_attr(feature="serde", serde(deserialize_with="deserialize_thickness_value"))]
401 l: i32,
402 #[cfg_attr(feature="serde", serde(deserialize_with="deserialize_thickness_value"))]
403 r: i32,
404 #[cfg_attr(feature="serde", serde(deserialize_with="deserialize_thickness_value"))]
405 t: i32,
406 #[cfg_attr(feature="serde", serde(deserialize_with="deserialize_thickness_value"))]
407 b: i32,
408}
409
410impl Thickness {
411 pub const fn new(l: i32, t: i32, r: i32, b: i32) -> Self {
412 assert!(l >= -(u16::MAX as u32 as i32) && l <= u16::MAX as u32 as i32);
413 assert!(t >= -(u16::MAX as u32 as i32) && t <= u16::MAX as u32 as i32);
414 assert!(r >= -(u16::MAX as u32 as i32) && r <= u16::MAX as u32 as i32);
415 assert!(b >= -(u16::MAX as u32 as i32) && b <= u16::MAX as u32 as i32);
416 Thickness { l, t, r, b }
417 }
418
419 pub const unsafe fn new_unchecked(l: i32, t: i32, r: i32, b: i32) -> Self {
423 Thickness { l, t, r, b }
424 }
425
426 pub const fn all(a: i32) -> Thickness {
427 assert!(a >= -(u16::MAX as u32 as i32) && a <= u16::MAX as u32 as i32);
428 Thickness { l: a, t: a, r: a, b: a }
429 }
430
431 pub fn l(self) -> i32 { self.l }
432
433 pub fn t(self) -> i32 { self.t }
434
435 pub fn r(self) -> i32 { self.r }
436
437 pub fn b(self) -> i32 { self.b }
438
439 pub fn align(inner: Vector, outer: Vector, h_align: HAlign, v_align: VAlign) -> Thickness {
440 let h_neg = inner.x as u16 > outer.x as u16;
441 let (outer_x, inner_x) = if h_neg { (inner.x, outer.x) } else { (outer.x, inner.x) };
442 let w = (outer_x as u16) - (inner_x as u16);
443 let (l, r) = match h_align {
444 HAlign::Left => (0, w),
445 HAlign::Right => (w, 0),
446 HAlign::Center => {
447 let l = w / 2;
448 let r = w - l;
449 (l, r)
450 }
451 };
452 let v_neg = inner.y as u16 > outer.y as u16;
453 let (outer_y, inner_y) = if v_neg { (inner.y, outer.y) } else { (outer.y, inner.y) };
454 let h = (outer_y as u16) - (inner_y as u16);
455 let (t, b) = match v_align {
456 VAlign::Top => (0, h),
457 VAlign::Bottom => (h, 0),
458 VAlign::Center => {
459 let t = h / 2;
460 let b = h - t;
461 (t, b)
462 }
463 };
464 let l = l as u32 as i32;
465 let t = t as u32 as i32;
466 let r = r as u32 as i32;
467 let b = b as u32 as i32;
468 Thickness {
469 l: if h_neg { -l } else { l },
470 t: if v_neg { -t } else { t },
471 r: if h_neg { -r } else { r },
472 b: if v_neg { -b } else { b }
473 }
474 }
475
476 fn shrink_near(thickness: u16, rect: (i16, i16)) -> (i16, i16) {
477 let thickness = min(thickness, rect.1 as u16);
478 (rect.0.wrapping_add(thickness as i16), rect.1.wrapping_sub(thickness as i16))
479 }
480
481 fn shrink_far(thickness: u16, rect: (i16, i16)) -> (i16, i16) {
482 let thickness = min(thickness, rect.1 as u16);
483 (rect.0, rect.1.wrapping_sub(thickness as i16))
484 }
485
486 fn expand_near(thickness: u16, rect: (i16, i16)) -> (i16, i16) {
487 let thickness = min(thickness, u16::MAX - (rect.1 as u16));
488 (rect.0.wrapping_sub(thickness as i16), rect.1.wrapping_add(thickness as i16))
489 }
490
491 fn expand_far(thickness: u16, rect: (i16, i16)) -> (i16, i16) {
492 let thickness = min(thickness, u16::MAX - (rect.1 as u16));
493 (rect.0, rect.1.wrapping_add(thickness as i16))
494 }
495
496 pub fn shrink_rect(self, rect: Rect) -> Rect {
497 let (l, w) = if self.l < 0 {
498 Self::expand_near((-self.l) as u32 as u16, (rect.l(), rect.w()))
499 } else {
500 Self::shrink_near(self.l as u32 as u16, (rect.l(), rect.w()))
501 };
502 let (t, h) = if self.t < 0 {
503 Self::expand_near((-self.t) as u32 as u16, (rect.t(), rect.h()))
504 } else {
505 Self::shrink_near(self.t as u32 as u16, (rect.t(), rect.h()))
506 };
507 let (l, w) = if self.r < 0 {
508 Self::expand_far((-self.r) as u32 as u16, (l, w))
509 } else {
510 Self::shrink_far(self.r as u32 as u16, (l, w))
511 };
512 let (t, h) = if self.b < 0 {
513 Self::expand_far((-self.b) as u32 as u16, (t, h))
514 } else {
515 Self::shrink_far(self.b as u32 as u16, (t, h))
516 };
517 Rect { tl: Point { x: l, y: t }, size: Vector { x: w, y: h } }
518 }
519
520 pub fn expand_rect(self, rect: Rect) -> Rect {
521 (-self).shrink_rect(rect)
522 }
523
524 pub fn shrink_rect_size(self, rect_size: Vector) -> Vector {
525 self.shrink_rect(Rect { tl: Point { x: 0, y: 0 }, size: rect_size }).size
526 }
527
528 pub fn expand_rect_size(self, rect_size: Vector) -> Vector {
529 self.expand_rect(Rect { tl: Point { x: 0, y: 0 }, size: rect_size }).size
530 }
531
532 pub fn shrink_band_h(self, band_h: i16) -> i16 {
533 let (_, h) = if self.t < 0 {
534 Self::expand_near((-self.t) as u32 as u16, (0, band_h))
535 } else {
536 Self::shrink_near(self.t as u32 as u16, (0, band_h))
537 };
538 h
539 }
540
541 pub fn expand_band_h(self, band_h: i16) -> i16 {
542 (-self).shrink_band_h(band_h)
543 }
544
545 pub fn shrink_band_w(self, band_w: i16) -> i16 {
546 let (_, w) = if self.l < 0 {
547 Self::expand_near((-self.t) as u32 as u16, (0, band_w))
548 } else {
549 Self::shrink_near(self.t as u32 as u16, (0, band_w))
550 };
551 w
552 }
553
554 pub fn expand_band_w(self, band_w: i16) -> i16 {
555 (-self).shrink_band_w(band_w)
556 }
557
558 fn add_side(this: i32, other: i32) -> i32 {
559 if this < 0 {
560 if other < 0 {
561 -(((-this) as u32 as u16).saturating_add((-other) as u32 as u16) as u32 as i32)
562 } else {
563 other + this
564 }
565 } else {
566 if other > 0 {
567 (this as u32 as u16).saturating_add(other as u32 as u16) as u32 as i32
568 } else {
569 other + this
570 }
571 }
572 }
573}
574
575impl Add for Thickness {
576 type Output = Self;
577
578 fn add(self, other: Self) -> Self {
579 let l = Self::add_side(self.l, other.l);
580 let t = Self::add_side(self.t, other.t);
581 let r = Self::add_side(self.r, other.r);
582 let b = Self::add_side(self.b, other.b);
583 Thickness { l, t, r, b }
584 }
585}
586
587impl AddAssign for Thickness {
588 fn add_assign(&mut self, other: Self) {
589 *self = *self + other;
590 }
591}
592
593impl Sub for Thickness {
594 type Output = Self;
595
596 fn sub(self, other: Self) -> Self {
597 self + (-other)
598 }
599}
600
601impl SubAssign for Thickness {
602 fn sub_assign(&mut self, other: Self) {
603 *self = *self - other;
604 }
605}
606
607impl Neg for Thickness {
608 type Output = Self;
609
610 fn neg(self) -> Self {
611 Thickness { l: -self.l, t: -self.t, r: -self.r, b: -self.b }
612 }
613}
614
615impl Index<Side> for Thickness {
616 type Output = i32;
617
618 fn index(&self, index: Side) -> &i32 {
619 match index {
620 Side::Left => &self.l,
621 Side::Top => &self.t,
622 Side::Right => &self.r,
623 Side::Bottom => &self.b
624 }
625 }
626}
627
628impl IndexMut<Side> for Thickness {
629 fn index_mut(&mut self, index: Side) -> &mut i32 {
630 match index {
631 Side::Left => &mut self.l,
632 Side::Top => &mut self.t,
633 Side::Right => &mut self.r,
634 Side::Bottom => &mut self.b
635 }
636 }
637}
638
639macro_attr! {
640 #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
641 #[derive(Eq, PartialEq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
642 #[derive(EnumDisplay!, EnumFromStr!)]
643 pub enum HAlign { Left, Center, Right }
644}
645
646macro_attr! {
647 #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
648 #[derive(Eq, PartialEq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
649 #[derive(EnumDisplay!, EnumFromStr!)]
650 pub enum VAlign { Top, Center, Bottom }
651}
652
653pub struct RectPoints {
654 rect: Rect,
655 x: i16,
656}
657
658impl Iterator for RectPoints {
659 type Item = Point;
660
661 fn next(&mut self) -> Option<Point> {
662 if self.rect.is_empty() {
663 return None;
664 }
665 let item = Point { x: self.x, y: self.rect.t() };
666 self.x = self.x.wrapping_add(1);
667 if self.x == self.rect.r() {
668 self.x = self.rect.l();
669 self.rect.tl = Point { x: self.x, y: self.rect.t().wrapping_add(1) };
670 self.rect.size = Vector { x: self.rect.w(), y: self.rect.h().wrapping_sub(1) };
671 }
672 Some(item)
673 }
674
675 fn size_hint(&self) -> (usize, Option<usize>) {
676 let len = self.rect.area() - (self.x.wrapping_sub(self.rect.l()) as u16 as u32);
677 if len as usize as u32 == len {
678 (len as usize, Some(len as usize))
679 } else {
680 (usize::MAX, None)
681 }
682 }
683
684 fn count(self) -> usize { self.size_hint().1.unwrap() }
685
686 fn last(self) -> Option<Point> {
687 if self.rect.is_empty() { None } else { Some(self.rect.br_inner()) }
688 }
689
690 fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
691 if let Some(rem) = self.size_hint().1.and_then(|len| n.checked_sub(len)).and_then(NonZeroUsize::new) {
692 self.x = self.rect.l();
693 self.rect.tl = self.rect.bl();
694 return Err(rem);
695 }
696 let n = n as u32;
697 let current_line_last = self.rect.r().wrapping_sub(self.x) as u16 as u32;
698 if n < current_line_last {
699 self.x = self.x.wrapping_add(n as u16 as i16);
700 return Ok(());
701 }
702 let n = n - current_line_last;
703 let skip_lines = 1i16.wrapping_add((n / self.rect.w() as u32) as u16 as i16);
704 self.rect.tl = Point { x: self.rect.l(), y: self.rect.t().wrapping_add(skip_lines) };
705 self.rect.size = Vector { x: self.rect.w(), y: self.rect.h().wrapping_sub(skip_lines) };
706 self.x = (n % self.rect.w() as u32) as u16 as i16;
707 Ok(())
708 }
709}
710
711impl FusedIterator for RectPoints { }
712
713#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
714#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
715pub struct Rect {
716 pub tl: Point,
717 pub size: Vector,
718}
719
720impl Rect {
721 pub fn from_tl_br(tl: Point, br: Point) -> Rect {
722 Rect { tl, size: br.offset_from(tl) }
723 }
724
725 pub fn from_h_v_ranges(h_range: Range1d, v_range: Range1d) -> Rect {
726 Rect::from_tl_br(
727 Point { x: h_range.start, y: v_range.start },
728 Point { x: h_range.end, y: v_range.end }
729 )
730 }
731
732 pub fn is_empty(self) -> bool { self.w() == 0 || self.h() == 0 }
733
734 pub fn w(self) -> i16 { self.size.x }
735
736 pub fn h(self) -> i16 { self.size.y }
737
738 pub fn l(self) -> i16 { self.tl.x }
739
740 pub fn t(self) -> i16 { self.tl.y }
741
742 pub fn r(self) -> i16 { self.tl.x.wrapping_add(self.size.x) }
743
744 pub fn b(self) -> i16 { self.tl.y.wrapping_add(self.size.y) }
745
746 pub fn tr(self) -> Point { Point { x: self.r(), y: self.t() } }
747
748 pub fn bl(self) -> Point { Point { x: self.l(), y: self.b() } }
749
750 pub fn br(self) -> Point { Point { x: self.r(), y: self.b() } }
751
752 pub fn r_inner(self) -> i16 {
753 self.l().wrapping_add((self.size.x as u16).saturating_sub(1) as i16)
754 }
755
756 pub fn b_inner(self) -> i16 {
757 self.t().wrapping_add((self.size.y as u16).saturating_sub(1) as i16)
758 }
759
760 pub fn tr_inner(self) -> Point { Point { x: self.r_inner(), y: self.t() } }
761
762 pub fn bl_inner(self) -> Point { Point { x: self.l(), y: self.b_inner() } }
763
764 pub fn br_inner(self) -> Point { Point { x: self.r_inner(), y: self.b_inner() } }
765
766 pub fn area(self) -> u32 { self.size.rect_area() }
767
768 pub fn points(self) -> RectPoints { RectPoints { rect: self, x: self.l() } }
769
770 pub fn h_range(self) -> Range1d { Range1d { start: self.l(), end: self.r() } }
771
772 pub fn v_range(self) -> Range1d { Range1d { start: self.t(), end: self.b() } }
773
774 pub fn contains(self, p: Point) -> bool {
775 self.h_range().contains(p.x) && self.v_range().contains(p.y)
776 }
777
778 pub fn intersect(self, other: Rect) -> Rect {
779 let h = self.h_range().intersect(other.h_range());
780 let v = self.v_range().intersect(other.v_range());
781 Rect::from_h_v_ranges(h, v)
782 }
783
784 pub fn intersect_h_band(self, band: HBand) -> Rect {
785 let v = self.v_range().intersect(band.v_range());
786 Rect::from_h_v_ranges(self.h_range(), v)
787 }
788
789 pub fn intersect_v_band(self, band: VBand) -> Rect {
790 let h = self.h_range().intersect(band.h_range());
791 Rect::from_h_v_ranges(h, self.v_range())
792 }
793
794 pub fn union(self, other: Rect) -> Option<Either<Either<HBand, VBand>, Rect>> {
795 if other.is_empty() { return Some(Right(self)); }
796 if self.is_empty() { return Some(Right(other)); }
797 let hr = self.h_range().union(other.h_range());
798 let vr = self.v_range().union(other.v_range());
799 if let Some(hr) = hr {
800 if let Some(vr) = vr {
801 Some(Right(Rect::from_h_v_ranges(hr, vr)))
802 } else {
803 Some(Left(Right(VBand::from_h_range(hr).unwrap())))
804 }
805 } else {
806 if let Some(vr) = vr {
807 Some(Left(Left(HBand::from_v_range(vr).unwrap())))
808 } else {
809 None
810 }
811 }
812 }
813
814 pub fn union_intersect(self, union_with: Rect, intersect_with: Rect) -> Rect {
815 match self.union(union_with) {
816 None => intersect_with,
817 Some(Right(rect)) => rect.intersect(intersect_with),
818 Some(Left(Right(v_band))) => Rect {
819 tl: Point { x: v_band.l, y: intersect_with.t() },
820 size: Vector { x: v_band.w.get(), y: intersect_with.h() }
821 },
822 Some(Left(Left(h_band))) => Rect {
823 tl: Point { y: h_band.t, x: intersect_with.l() },
824 size: Vector { y: h_band.h.get(), x: intersect_with.w() }
825 },
826 }
827 }
828
829 pub fn offset(self, d: Vector) -> Rect {
830 Rect { tl: self.tl.offset(d), size: self.size }
831 }
832
833 pub fn relative_to(self, base: Point) -> Rect {
834 Rect { tl: self.tl.relative_to(base), size: self.size }
835 }
836
837 pub fn absolute_with(self, base: Point) -> Rect {
838 Rect { tl: self.tl.absolute_with(base), size: self.size }
839 }
840
841 pub fn t_line(self) -> Rect {
842 let height = min(1, self.size.y as u16) as i16;
843 Rect { tl: self.tl, size: Vector { x: self.size.x, y: height } }
844 }
845
846 pub fn b_line(self) -> Rect {
847 let height = min(1, self.size.y as u16) as i16;
848 Rect {
849 tl: Point { x: self.l(), y: self.b().wrapping_sub(height) },
850 size: Vector { x: self.size.x, y: height }
851 }
852 }
853
854 pub fn l_line(self) -> Rect {
855 let width = min(1, self.size.x as u16) as i16;
856 Rect { tl: self.tl, size: Vector { x: width, y: self.size.y } }
857 }
858
859 pub fn r_line(self) -> Rect {
860 let width = min(1, self.size.x as u16) as i16;
861 Rect {
862 tl: Point { x: self.r().wrapping_sub(width), y: self.t() },
863 size: Vector { x: width, y: self.size.y }
864 }
865 }
866}
867
868#[cfg(test)]
869impl Arbitrary for Rect {
870 fn arbitrary(g: &mut Gen) -> Self {
871 let a = <(Point, Point)>::arbitrary(g);
872 Rect::from_tl_br(a.0, a.1)
873 }
874}
875
876#[cfg(test)]
877mod tests {
878 use quickcheck::TestResult;
879 use quickcheck_macros::quickcheck;
880 use crate::*;
881
882 #[test]
883 fn test_range_iterator() {
884 let r = Range1d::new(0, 29).step_by(2);
885 assert_eq!(r.count(), 15);
886 }
887
888 #[quickcheck]
889 fn rect_area(r: Rect) -> bool {
890 r.area() == r.size.rect_area()
891 }
892
893 #[quickcheck]
894 #[allow(clippy::bool_comparison)]
895 fn rect_is_empty_area(r: Rect) -> bool {
896 !r.is_empty() == (r.area() > 0)
897 }
898
899 #[quickcheck]
900 fn null_size_rect_is_empty(tl: Point) -> bool {
901 Rect { tl, size: Vector::null() }.is_empty()
902 }
903
904 #[quickcheck]
905 fn rect_empty_intersect(tl1: Point, r2: Rect) -> bool {
906 let r1 = Rect { tl: tl1, size: Vector::null() };
907 r1.intersect(r2) == r1
908 }
909
910 #[quickcheck]
911 fn rect_intersect_empty(r1: Rect, tl2: Point) -> bool {
912 let r2 = Rect { tl: tl2, size: Vector::null() };
913 r1.is_empty() || r1.contains(r1.intersect(r2).tl)
914 }
915
916 #[quickcheck]
917 fn rect_intersect_contains(r1: Rect, r2: Rect, p: Point) -> bool {
918 r1.intersect(r2).contains(p) || !(r1.contains(p) && r2.contains(p))
919 }
920
921 #[quickcheck]
922 fn rect_union_contains(r1: Rect, r2: Rect, p: Point) -> bool {
923 r1.union(r2).map_or(true, |u| u.either(|_| true, |u| u.contains(p))) || !(r1.contains(p) || r2.contains(p))
924 }
925
926 #[quickcheck]
927 fn rect_empty_h_union(tl1: Point, r2: Rect, w: i16) -> bool {
928 let r1 = Rect { tl: tl1, size: Vector { x: w, y: 0} };
929 r2.is_empty() || r1.union(r2).unwrap().right().unwrap() == r2
930 }
931
932 #[quickcheck]
933 fn rect_union_empty_h(r1: Rect, tl2: Point, w: i16) -> bool {
934 let r2 = Rect { tl: tl2, size: Vector { x: w, y: 0 } };
935 r1.union(r2).unwrap().right().unwrap() == r1
936 }
937
938 #[quickcheck]
939 fn rect_empty_w_union(tl1: Point, r2: Rect, h: i16) -> bool {
940 let r1 = Rect { tl: tl1, size: Vector { x: 0, y: h } };
941 r2.is_empty() || r1.union(r2).unwrap().right().unwrap() == r2
942 }
943
944 #[quickcheck]
945 fn rect_union_empty_w(r1: Rect, tl2: Point, h: i16) -> bool {
946 let r2 = Rect { tl: tl2, size: Vector { x: 0, y: h } };
947 r1.union(r2).unwrap().right().unwrap() == r1
948 }
949
950 #[quickcheck]
951 fn rect_contains_all_self_points(r: Rect) -> TestResult {
952 if r.area() > 100000 { return TestResult::discard(); }
953 TestResult::from_bool(r.points().all(|x| r.contains(x)))
954 }
955}