point_index/
lib.rs

1//! a point library for working with 2d arrays or vectors.
2//!
3//! it has all the cardinal direction for point addition as well as scalar multiplication.
4//! # Examples
5//! here are a couple of examples of array accessing
6//! ```
7//! use point_index::*;
8//! let mut vec = vec![vec![0, 1, 2], vec![3, 4, 5], vec![6, 7, 8]];
9//! let mut point1 = Point { x: 1, y: 1 };
10//! assert_eq!(vec[point1], 4);
11//! // Up is the same as Point {x: 0, y: -1}
12//! let point2 = point1 + UP;
13//! assert_eq!(vec[point2], 1);
14//! // Down is the same as Point {x: 0, y: 1}
15//! let point3 = point2 + DOWN * 2;
16//! assert_eq!(vec[point3], 7);
17//! // Up left is the same as Point {x: -1, y: -1}
18//! let point4 = point1 + UP_LEFT;
19//! assert_eq!(vec[point4], 0)
20//! ```
21//! here is a sample of examples of array mutation
22//! ```
23//! use point_index::*;
24//! let mut arr = [[0; 10]; 10];
25//! // down right is the same as Point {x: 1, y: 1}
26//! for x in 0 .. 10{
27//!     arr[DOWN_RIGHT * x] = x
28//! }
29//! assert_eq!(
30//!     arr,
31//!    [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
32//!     [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
33//!     [0, 0, 2, 0, 0, 0, 0, 0, 0, 0],
34//!     [0, 0, 0, 3, 0, 0, 0, 0, 0, 0],
35//!     [0, 0, 0, 0, 4, 0, 0, 0, 0, 0],
36//!     [0, 0, 0, 0, 0, 5, 0, 0, 0, 0],
37//!     [0, 0, 0, 0, 0, 0, 6, 0, 0, 0],
38//!     [0, 0, 0, 0, 0, 0, 0, 7, 0, 0],
39//!     [0, 0, 0, 0, 0, 0, 0, 0, 8, 0],
40//!     [0, 0, 0, 0, 0, 0, 0, 0, 0, 9]]
41//!
42//! )
43//! ```
44use std::mem;
45use std::ops::{Add, Index, IndexMut, Mul, Sub};
46pub const UP: Point = Point { x: 0, y: -1 };
47pub const DOWN: Point = Point { x: 0, y: 1 };
48pub const LEFT: Point = Point { x: -1, y: 0 };
49pub const RIGHT: Point = Point { x: 1, y: 0 };
50pub const UP_LEFT: Point = Point { x: -1, y: -1 };
51pub const UP_RIGHT: Point = Point { x: 1, y: -1 };
52pub const DOWN_LEFT: Point = Point { x: -1, y: 1 };
53pub const DOWN_RIGHT: Point = Point { x: 1, y: 1 };
54
55
56#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
57pub struct Point {
58    pub x: isize,
59    pub y: isize,
60}
61
62impl Point {
63    fn new(x: isize, y: isize) -> Point {
64        Point {x, y}
65    }
66}
67
68impl Add for Point {
69    type Output = Point;
70
71    fn add(self, other: Point) -> Point {
72        Point::new(self.x + other.x, self.y + other.y)
73    }
74}
75
76impl Sub for Point {
77    type Output = Point;
78
79    fn sub(self, other: Point) -> Point {
80        Point::new(self.x - other.x, self.y - other.y)
81    }
82}
83
84impl Mul<isize> for Point {
85    type Output = Point;
86
87    fn mul(self, other: isize) -> Point {
88        Point::new(self.x * other, self.y * other)
89    }
90}
91
92impl<A> Index<Point> for Vec<Vec<A>> {
93    type Output = A;
94
95    fn index(&self, index: Point) -> &A {
96        let x: usize = index.x.try_into().unwrap();
97        let y: usize = index.y.try_into().unwrap();
98        &self[y][x]
99    }
100}
101
102impl<A, const SIZE_OUTER: usize, const SIZE_INNER: usize> Index<Point> for [[A; SIZE_INNER]; SIZE_OUTER] {
103    type Output = A;
104
105    fn index(&self, index: Point) -> &A {
106        let x: usize = index.x.try_into().unwrap();
107        let y: usize = index.y.try_into().unwrap();
108        &self[y][x]
109    }
110}
111
112impl <A> IndexMut<Point> for Vec<Vec<A>> {
113    fn index_mut(&mut self, index: Point) -> &mut A {
114        let x: usize = index.x.try_into().unwrap();
115        let y: usize = index.y.try_into().unwrap();
116        &mut self[y][x]
117    }
118}
119
120impl <A, const SIZE_OUTER: usize, const SIZE_INNER: usize> IndexMut<Point> for [[A; SIZE_INNER]; SIZE_OUTER] {
121    fn index_mut(&mut self, index: Point) -> &mut A {
122        let x: usize = index.x.try_into().unwrap();
123        let y: usize = index.y.try_into().unwrap();
124        &mut self[y][x]
125    }
126}
127
128
129/// This trait is used to get a value from a 2d array. If the operation fails, either because the
130/// point is out of bounds or because the conversion from isize to usize fails, None is returned.
131pub trait Get{
132    type Output;
133    fn get_option(&self, point: Point) -> Option<&Self::Output>;
134    fn get_mut_option(&mut self, point: Point) -> Option<&mut Self::Output>;
135}
136
137impl<A> Get for Vec<Vec<A>> {
138    type Output = A;
139
140    fn get_option(&self, point: Point) -> Option<&Self::Output> {
141        let x: usize = point.x.try_into().ok()?;
142        let y: usize = point.y.try_into().ok()?;
143        self.get(y)?.get(x)
144    }
145
146    fn get_mut_option(&mut self, point: Point) -> Option<&mut Self::Output> {
147        let x: usize = point.x.try_into().ok()?;
148        let y: usize = point.y.try_into().ok()?;
149        self.get_mut(y)?.get_mut(x)
150    }
151}
152
153impl<A, const SIZE_INNER: usize, const SIZE_OUTER: usize> Get for [[A; SIZE_INNER]; SIZE_OUTER] {
154    type Output = A;
155
156    fn get_option(&self, point: Point) -> Option<&Self::Output> {
157        let x: usize = point.x.try_into().ok()?;
158        let y: usize = point.y.try_into().ok()?;
159        self.get(y)?.get(x)
160    }
161
162    fn get_mut_option(&mut self, point: Point) -> Option<&mut Self::Output> {
163        let x: usize = point.x.try_into().ok()?;
164        let y: usize = point.y.try_into().ok()?;
165        self.get_mut(y)?.get_mut(x)
166    }
167}
168
169
170/// This trait is used to set a value in a 2d array if it succeeds then the item that was at that
171/// index is returned. If the operation fails, either because the point is out of bounds or because
172/// the conversion from isize to usize fails, None is returned.
173pub trait Set{
174    type Output;
175    fn set(&mut self, point: Point, value: Self::Output) -> Option<Self::Output>;
176}
177
178impl<A> Set for Vec<Vec<A>> {
179    type Output = A;
180
181    fn set(&mut self, point: Point, value: Self::Output) -> Option<Self::Output> {
182        let x: usize = point.x.try_into().ok()?;
183        let y: usize = point.y.try_into().ok()?;
184        let inner = self.get_mut(y)?;
185        let location = inner.get_mut(x)?;
186        Some(mem::replace(location, value))
187    }
188}
189
190impl<A, const SIZE_INNER: usize, const SIZE_OUTER: usize> Set for [[A; SIZE_INNER]; SIZE_OUTER] {
191    type Output = A;
192
193    fn set(&mut self, point: Point, value: Self::Output) -> Option<Self::Output> {
194        let x: usize = point.x.try_into().ok()?;
195        let y: usize = point.y.try_into().ok()?;
196        Some(mem::replace(self.get_mut(y)?.get_mut(x)?, value))
197    }
198}
199
200
201
202
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207
208    #[test]
209    fn it_works() {
210        let v = vec![vec![0; 3]; 3];
211
212        assert_eq!(v[Point::new(1, 1)], 0);
213    }
214    #[test]
215    fn it_works_array() {
216        let v = [[0; 3]; 3];
217
218        assert_eq!(v[Point::new(1, 1)], 0);
219    }
220    #[test]
221    fn basic_mutation() {
222        let mut v = vec![vec![0; 3]; 3];
223        let point = Point::new(1, 1);
224        v[point] = 1;
225
226        assert_eq!(v[point], 1);
227    }
228    #[test]
229    fn basic_mutation_array() {
230        let mut v = [[0; 3]; 3];
231        let point = Point::new(1, 1);
232        v[point] = 1;
233
234        assert_eq!(v[point], 1);
235    }
236    #[test]
237    fn basic_point_addition() {
238        let v = [[1, 1, 1, 2]; 3];
239        let point = Point::new(1, 1) + Point::new(2, 0);
240        assert_eq!(v[point], 2);
241    }
242    #[test]
243    fn basic_multiplication() {
244        let v = [[1, 1, 1, 2]; 3];
245        let point = Point::new(1, 1) + RIGHT * 2;
246        assert_eq!(v[point], 2);
247    }
248}