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}