1use crate::grid::bounds::BoundsError;
2use crate::grid::Grid;
3use crate::location::{Location, LocationLike};
4
5pub trait GridSetter: Grid {
11 #[must_use = "discarded return value of replace_unchecked; consider using set_unchecked"]
24 unsafe fn replace_unchecked(&mut self, location: Location, value: Self::Item) -> Self::Item;
25
26 unsafe fn set_unchecked(&mut self, location: Location, value: Self::Item);
39
40 #[inline]
44 fn replace(
45 &mut self,
46 location: impl LocationLike,
47 value: Self::Item,
48 ) -> Result<Self::Item, BoundsError> {
49 self.check_location(location)
50 .map(move |loc| unsafe { self.replace_unchecked(loc, value) })
51 }
52
53 #[inline]
56 fn set(&mut self, location: impl LocationLike, value: Self::Item) -> Result<(), BoundsError> {
57 self.check_location(location)
58 .map(move |loc| unsafe { self.set_unchecked(loc, value) })
59 }
60}
61
62impl<G: GridSetter> GridSetter for &mut G {
63 #[inline]
64 unsafe fn replace_unchecked(&mut self, location: Location, value: Self::Item) -> Self::Item {
65 G::replace_unchecked(self, location, value)
66 }
67
68 #[inline]
69 unsafe fn set_unchecked(&mut self, location: Location, value: Self::Item) {
70 G::set_unchecked(self, location, value)
71 }
72
73 #[inline]
74 fn replace(
75 &mut self,
76 location: impl LocationLike,
77 value: Self::Item,
78 ) -> Result<Self::Item, BoundsError> {
79 G::replace(self, location, value)
80 }
81
82 #[inline]
83 fn set(&mut self, location: impl LocationLike, value: Self::Item) -> Result<(), BoundsError> {
84 G::set(self, location, value)
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use crate::grid::setter::*;
91 use crate::prelude::*;
92 use crate::range::RangeError;
93 use core::mem::replace;
94
95 #[derive(Debug, Clone, Default)]
97 struct SimpleGrid<T> {
98 cells: [T; 4],
99 }
100
101 impl<T> SimpleGrid<T> {
102 fn index_of(loc: Location) -> usize {
103 match (loc.row.0, loc.column.0) {
104 (0, 0) => 0,
105 (0, 1) => 1,
106 (1, 0) => 2,
107 (1, 1) => 3,
108 _ => unreachable!(),
109 }
110 }
111 }
112
113 impl<T> GridBounds for SimpleGrid<T> {
114 fn dimensions(&self) -> Vector {
115 Vector::new(2, 2)
116 }
117
118 fn root(&self) -> Location {
119 Location::zero()
120 }
121 }
122
123 impl<T> Grid for SimpleGrid<T> {
124 type Item = T;
125
126 unsafe fn get_unchecked(&self, location: Location) -> &T {
127 self.cells.get_unchecked(Self::index_of(location))
128 }
129 }
130
131 impl<T> GridSetter for SimpleGrid<T> {
132 unsafe fn replace_unchecked(&mut self, location: Location, value: T) -> T {
133 replace(
134 self.cells.get_unchecked_mut(Self::index_of(location)),
135 value,
136 )
137 }
138
139 unsafe fn set_unchecked(&mut self, location: Location, value: T) {
140 *self.cells.get_unchecked_mut(Self::index_of(location)) = value;
141 }
142 }
143
144 static TEST_ROWS: [(Row, Option<RowRangeError>); 3] = [
145 (Row(-5), Some(RangeError::TooLow(Row(0)))),
146 (Row(1), None),
147 (Row(5), Some(RangeError::TooHigh(Row(2)))),
148 ];
149
150 static TEST_COLUMNS: [(Column, Option<ColumnRangeError>); 3] = [
151 (Column(-10), Some(RangeError::TooLow(Column(0)))),
152 (Column(0), None),
153 (Column(10), Some(RangeError::TooHigh(Column(2)))),
154 ];
155
156 #[test]
157 fn test_set() {
158 let mut grid: SimpleGrid<Option<&'static str>> = SimpleGrid::default();
159
160 for &(row, row_error) in &TEST_ROWS {
161 for &(column, column_error) in &TEST_COLUMNS {
162 let location = row + column;
163
164 let result = grid.set(location, Some("Hello"));
165
166 match (row_error, column_error) {
167 (Some(row), Some(column)) => {
168 assert_eq!(result, Err(BoundsError::Both { row, column }))
169 }
170 (Some(row), None) => assert_eq!(result, Err(BoundsError::Row(row))),
171 (None, Some(column)) => assert_eq!(result, Err(BoundsError::Column(column))),
172 (None, None) => assert_eq!(result, Ok(())),
173 }
174 }
175 }
176
177 assert_eq!(&grid.cells, &[None, None, Some("Hello"), None]);
178 }
179
180 #[test]
181 fn test_replace() {
182 let mut grid: SimpleGrid<Option<&'static str>> = SimpleGrid::default();
183 grid.set((1, 0), Some("Hello")).unwrap();
184
185 for &(row, row_error) in &TEST_ROWS {
186 for &(column, column_error) in &TEST_COLUMNS {
187 let location = row + column;
188
189 let result = grid.replace(location, Some("World"));
190
191 match (row_error, column_error) {
192 (Some(row), Some(column)) => {
193 assert_eq!(result, Err(BoundsError::Both { row, column }))
194 }
195 (Some(row), None) => assert_eq!(result, Err(BoundsError::Row(row))),
196 (None, Some(column)) => assert_eq!(result, Err(BoundsError::Column(column))),
197 (None, None) => assert_eq!(result, Ok(Some("Hello"))),
198 }
199 }
200 }
201
202 assert_eq!(&grid.cells, &[None, None, Some("World"), None]);
203 }
204}