wfc/
wrap.rs

1use coord_2d::{Coord, Size};
2
3pub trait Wrap: Copy + Send + Sync + private::Sealed {
4    #[doc(hidden)]
5    fn normalize_coord(coord: Coord, size: Size) -> Option<Coord>;
6}
7
8#[derive(Clone, Copy, Debug)]
9pub struct WrapNone;
10
11#[derive(Clone, Copy, Debug)]
12pub struct WrapX;
13
14#[derive(Clone, Copy, Debug)]
15pub struct WrapY;
16
17#[derive(Clone, Copy, Debug)]
18pub struct WrapXY;
19
20impl Wrap for WrapNone {
21    fn normalize_coord(coord: Coord, size: Size) -> Option<Coord> {
22        if coord.is_valid(size) {
23            Some(coord)
24        } else {
25            None
26        }
27    }
28}
29
30fn value_is_valid(value: i32, size: u32) -> bool {
31    value >= 0 && (value as u32) < size
32}
33
34fn normalize_value(value: i32, size: u32) -> i32 {
35    let value = value % size as i32;
36    if value < 0 {
37        value + size as i32
38    } else {
39        value
40    }
41}
42
43impl Wrap for WrapX {
44    fn normalize_coord(coord: Coord, size: Size) -> Option<Coord> {
45        if value_is_valid(coord.y, size.y()) {
46            let x = normalize_value(coord.x, size.x());
47            Some(Coord::new(x, coord.y))
48        } else {
49            None
50        }
51    }
52}
53
54impl Wrap for WrapXY {
55    fn normalize_coord(coord: Coord, size: Size) -> Option<Coord> {
56        Some(coord.normalize(size))
57    }
58}
59
60impl Wrap for WrapY {
61    fn normalize_coord(coord: Coord, size: Size) -> Option<Coord> {
62        if value_is_valid(coord.x, size.x()) {
63            let y = normalize_value(coord.y, size.y());
64            Some(Coord::new(coord.x, y))
65        } else {
66            None
67        }
68    }
69}
70
71mod private {
72    use super::*;
73
74    pub trait Sealed {}
75
76    impl Sealed for WrapX {}
77    impl Sealed for WrapY {}
78    impl Sealed for WrapXY {}
79    impl Sealed for WrapNone {}
80}
81
82#[cfg(test)]
83mod test {
84    use super::*;
85
86    #[test]
87    fn wraps() {
88        assert_eq! {
89            WrapNone::normalize_coord(Coord::new(2, 3), Size::new(4, 5)),
90            Some(Coord::new(2, 3))
91        };
92        assert_eq! {
93            WrapNone::normalize_coord(Coord::new(4, 3), Size::new(4, 5)),
94            None,
95        };
96        assert_eq! {
97            WrapX::normalize_coord(Coord::new(4, 3), Size::new(4, 5)),
98            Some(Coord::new(0, 3)),
99        };
100        assert_eq! {
101            WrapY::normalize_coord(Coord::new(4, 3), Size::new(4, 5)),
102            None,
103        };
104        assert_eq! {
105            WrapY::normalize_coord(Coord::new(2, 6), Size::new(4, 5)),
106            Some(Coord::new(2, 1)),
107        };
108        assert_eq! {
109            WrapXY::normalize_coord(Coord::new(2, 6), Size::new(4, 5)),
110            Some(Coord::new(2, 1)),
111        };
112    }
113}