int_vec_2d/
lib.rs

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