1use std::{
2 fmt,
3 ops::{Add, Index, IndexMut, Neg, Sub},
4};
5
6use num::{
7 CheckedAdd,
8 CheckedSub,
9 One,
10 traits::{SaturatingAdd, SaturatingSub},
11};
12
13use crate::CoordPair;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum Axis {
17 Y,
18 X,
19}
20
21impl Axis {
22 pub const ALL: [Self; 2] = [Self::Y, Self::X];
23
24 pub fn shift(self) -> Self {
25 match self {
26 Self::Y => Self::X,
27 Self::X => Self::Y,
28 }
29 }
30}
31
32impl fmt::Display for Axis {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 match self {
35 Self::Y => write!(f, "y"),
36 Self::X => write!(f, "x"),
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub enum Order {
43 Backwards,
44 Forwards,
45}
46
47impl Order {
48 pub const ALL: [Self; 2] = [Self::Backwards, Self::Forwards];
49
50 pub fn move_unit<C>(self, target: C) -> C
51 where
52 C: Add<Output = C> + Sub<Output = C> + One,
53 {
54 self.move_by(C::one(), target)
55 }
56
57 pub fn checked_move_unit<C>(self, target: &C) -> Option<C>
58 where
59 C: CheckedAdd + CheckedSub + One,
60 {
61 self.checked_move_by(&C::one(), target)
62 }
63
64 pub fn saturating_move_unit<C>(self, target: &C) -> C
65 where
66 C: SaturatingAdd + SaturatingSub + One,
67 {
68 self.saturating_move_by(&C::one(), target)
69 }
70
71 pub fn move_by<C>(self, magnitude: C, target: C) -> C
72 where
73 C: Add<Output = C> + Sub<Output = C>,
74 {
75 match self {
76 Self::Backwards => target - magnitude,
77 Self::Forwards => target + magnitude,
78 }
79 }
80
81 pub fn checked_move_by<C>(self, magnitude: &C, target: &C) -> Option<C>
82 where
83 C: CheckedAdd + CheckedSub,
84 {
85 match self {
86 Self::Backwards => target.checked_sub(magnitude),
87 Self::Forwards => target.checked_add(magnitude),
88 }
89 }
90
91 pub fn saturating_move_by<C>(self, magnitude: &C, target: &C) -> C
92 where
93 C: SaturatingAdd + SaturatingSub,
94 {
95 match self {
96 Self::Backwards => target.saturating_add(magnitude),
97 Self::Forwards => target.saturating_sub(magnitude),
98 }
99 }
100}
101
102impl fmt::Display for Order {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 match self {
105 Self::Backwards => write!(f, "-"),
106 Self::Forwards => write!(f, "+"),
107 }
108 }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
112pub enum Direction {
113 Up,
114 Left,
115 Down,
116 Right,
117}
118
119impl Direction {
120 pub const ALL: [Self; 4] = [Self::Up, Self::Left, Self::Down, Self::Right];
121
122 pub fn new(axis: Axis, order: Order) -> Self {
123 match (axis, order) {
124 (Axis::Y, Order::Backwards) => Self::Up,
125 (Axis::X, Order::Backwards) => Self::Left,
126 (Axis::Y, Order::Forwards) => Self::Down,
127 (Axis::X, Order::Forwards) => Self::Right,
128 }
129 }
130
131 pub fn axis(self) -> Axis {
132 match self {
133 Self::Up | Self::Down => Axis::Y,
134 Self::Left | Self::Right => Axis::X,
135 }
136 }
137
138 pub fn order(self) -> Order {
139 match self {
140 Self::Up | Self::Left => Order::Backwards,
141 Self::Down | Self::Right => Order::Forwards,
142 }
143 }
144
145 pub fn move_unit<C>(self, target: CoordPair<C>) -> CoordPair<C>
146 where
147 C: Add<Output = C> + Sub<Output = C> + One,
148 {
149 DirectionVec::unit(self).mov(target)
150 }
151
152 pub fn checked_move_unit<C>(
153 self,
154 target: &CoordPair<C>,
155 ) -> Option<CoordPair<C>>
156 where
157 C: CheckedAdd + CheckedSub + One + Clone,
158 {
159 DirectionVec::unit(self).as_ref().checked_move(target)
160 }
161
162 pub fn checked_move_unit_by_ref<C>(
163 self,
164 target: CoordPair<&C>,
165 ) -> Option<CoordPair<C>>
166 where
167 C: CheckedAdd + CheckedSub + One + Clone,
168 {
169 DirectionVec::unit(self).as_ref().checked_move_by_ref(target)
170 }
171
172 pub fn saturating_move_unit<C>(self, target: &CoordPair<C>) -> CoordPair<C>
173 where
174 C: SaturatingAdd + SaturatingSub + One + Clone,
175 {
176 DirectionVec::unit(self).as_ref().saturating_move(target)
177 }
178
179 pub fn saturating_move_unit_by_ref<C>(
180 self,
181 target: CoordPair<&C>,
182 ) -> CoordPair<C>
183 where
184 C: SaturatingAdd + SaturatingSub + One + Clone,
185 {
186 DirectionVec::unit(self).as_ref().saturating_move_by_ref(target)
187 }
188
189 pub fn move_by<C>(self, magnitude: C, target: CoordPair<C>) -> CoordPair<C>
190 where
191 C: Add<Output = C> + Sub<Output = C>,
192 {
193 DirectionVec { direction: self, magnitude }.mov(target)
194 }
195
196 pub fn checked_move_by<C>(
197 self,
198 magnitude: &C,
199 target: &CoordPair<C>,
200 ) -> Option<CoordPair<C>>
201 where
202 C: CheckedAdd + CheckedSub + Clone,
203 {
204 DirectionVec { direction: self, magnitude }.checked_move(target)
205 }
206
207 pub fn checked_move_by_ref_by<C>(
208 self,
209 magnitude: &C,
210 target: CoordPair<&C>,
211 ) -> Option<CoordPair<C>>
212 where
213 C: CheckedAdd + CheckedSub + Clone,
214 {
215 DirectionVec { direction: self, magnitude }.checked_move_by_ref(target)
216 }
217
218 pub fn saturating_move_by<C>(
219 self,
220 magnitude: &C,
221 target: &CoordPair<C>,
222 ) -> CoordPair<C>
223 where
224 C: SaturatingAdd + SaturatingSub + Clone,
225 {
226 self.saturating_move_by_ref_by(magnitude, target.as_ref())
227 }
228
229 pub fn saturating_move_by_ref_by<C>(
230 self,
231 magnitude: &C,
232 target: CoordPair<&C>,
233 ) -> CoordPair<C>
234 where
235 C: SaturatingAdd + SaturatingSub + Clone,
236 {
237 match self.axis() {
238 Axis::Y => CoordPair {
239 y: self.order().saturating_move_by(magnitude, target.y),
240 x: target.x.clone(),
241 },
242 Axis::X => CoordPair {
243 x: self.order().saturating_move_by(magnitude, target.x),
244 y: target.y.clone(),
245 },
246 }
247 }
248}
249
250impl fmt::Display for Direction {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 match self {
253 Self::Up => write!(f, "-y"),
254 Self::Left => write!(f, "-x"),
255 Self::Down => write!(f, "+y"),
256 Self::Right => write!(f, "+x"),
257 }
258 }
259}
260
261impl Neg for Direction {
262 type Output = Self;
263
264 fn neg(self) -> Self::Output {
265 match self {
266 Self::Up => Self::Down,
267 Self::Left => Self::Right,
268 Self::Right => Self::Left,
269 Self::Down => Self::Up,
270 }
271 }
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
275pub struct DirectionMap<T> {
276 pub up: T,
277 pub left: T,
278 pub down: T,
279 pub right: T,
280}
281
282impl<T> DirectionMap<T> {
283 pub fn from_dirs<F>(mut generator: F) -> DirectionMap<T>
284 where
285 F: FnMut(Direction) -> T,
286 {
287 Self {
288 up: generator(Direction::Up),
289 left: generator(Direction::Left),
290 down: generator(Direction::Down),
291 right: generator(Direction::Right),
292 }
293 }
294
295 pub fn map<F, U>(self, mut mapper: F) -> DirectionMap<U>
296 where
297 F: FnMut(T) -> U,
298 {
299 self.map_with_dirs(|elem, _| mapper(elem))
300 }
301
302 pub fn map_with_dirs<F, U>(self, mut mapper: F) -> DirectionMap<U>
303 where
304 F: FnMut(T, Direction) -> U,
305 {
306 DirectionMap {
307 up: mapper(self.up, Direction::Up),
308 left: mapper(self.left, Direction::Left),
309 down: mapper(self.down, Direction::Down),
310 right: mapper(self.right, Direction::Right),
311 }
312 }
313
314 pub fn as_ref(&self) -> DirectionMap<&T> {
315 DirectionMap {
316 up: &self.up,
317 left: &self.left,
318 down: &self.down,
319 right: &self.right,
320 }
321 }
322
323 pub fn as_mut(&mut self) -> DirectionMap<&mut T> {
324 DirectionMap {
325 up: &mut self.up,
326 left: &mut self.left,
327 down: &mut self.down,
328 right: &mut self.right,
329 }
330 }
331}
332
333impl<'a, T> DirectionMap<&'a T> {
334 pub fn copied(self) -> DirectionMap<T>
335 where
336 T: Copy,
337 {
338 self.map(|a| *a)
339 }
340
341 pub fn cloned(self) -> DirectionMap<T>
342 where
343 T: Clone,
344 {
345 self.map(Clone::clone)
346 }
347}
348
349impl<'a, T> DirectionMap<&'a mut T> {
350 pub fn copied(self) -> DirectionMap<T>
351 where
352 T: Copy,
353 {
354 self.map(|a| *a)
355 }
356
357 pub fn cloned(self) -> DirectionMap<T>
358 where
359 T: Clone,
360 {
361 self.map(|a| a.clone())
362 }
363
364 pub fn share(self) -> DirectionMap<&'a T> {
365 self.map(|a| &*a)
366 }
367}
368
369impl<T> DirectionMap<Option<T>> {
370 pub fn transpose(self) -> Option<DirectionMap<T>> {
371 Some(DirectionMap {
372 up: self.up?,
373 left: self.left?,
374 down: self.down?,
375 right: self.right?,
376 })
377 }
378
379 pub fn from_transposed(transposed: Option<DirectionMap<T>>) -> Self {
380 match transposed {
381 Some(table) => table.map(Some),
382 None => Self::from_dirs(|_| None),
383 }
384 }
385}
386
387impl<T, E> DirectionMap<Result<T, E>> {
388 pub fn transpose(self) -> Result<DirectionMap<T>, E> {
389 Ok(DirectionMap {
390 up: self.up?,
391 left: self.left?,
392 down: self.down?,
393 right: self.right?,
394 })
395 }
396
397 pub fn from_transposed(transposed: Result<DirectionMap<T>, E>) -> Self
398 where
399 E: Clone,
400 {
401 match transposed {
402 Ok(table) => table.map(Ok),
403 Err(error) => Self::from_dirs(|_| Err(error.clone())),
404 }
405 }
406}
407
408impl<T> Index<Direction> for DirectionMap<T> {
409 type Output = T;
410
411 fn index(&self, index: Direction) -> &Self::Output {
412 match index {
413 Direction::Up => &self.up,
414 Direction::Left => &self.left,
415 Direction::Down => &self.down,
416 Direction::Right => &self.right,
417 }
418 }
419}
420
421impl<T> Index<(Axis, Order)> for DirectionMap<T> {
422 type Output = T;
423
424 fn index(&self, (axis, order): (Axis, Order)) -> &Self::Output {
425 &self[Direction::new(axis, order)]
426 }
427}
428
429impl<T> IndexMut<Direction> for DirectionMap<T> {
430 fn index_mut(&mut self, index: Direction) -> &mut Self::Output {
431 match index {
432 Direction::Up => &mut self.up,
433 Direction::Left => &mut self.left,
434 Direction::Down => &mut self.down,
435 Direction::Right => &mut self.right,
436 }
437 }
438}
439
440impl<T> IndexMut<(Axis, Order)> for DirectionMap<T> {
441 fn index_mut(&mut self, (axis, order): (Axis, Order)) -> &mut Self::Output {
442 &mut self[Direction::new(axis, order)]
443 }
444}
445
446#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
447pub struct DirectionFlags {
448 bits: u8,
449}
450
451impl DirectionFlags {
452 pub fn new(map: DirectionMap<bool>) -> Self {
453 Self::packed([map, DirectionMap::default()])
454 }
455
456 pub fn packed(maps: [DirectionMap<bool>; 2]) -> Self {
457 let mut bits = 0_u8;
458 for map in maps.into_iter().rev() {
459 for direction in Direction::ALL.into_iter().rev() {
460 bits <<= 1;
461 bits |= u8::from(map[direction]);
462 }
463 }
464 Self { bits }
465 }
466
467 pub fn map(self) -> DirectionMap<bool> {
468 self.packed_maps()[0]
469 }
470
471 pub fn packed_maps(self) -> [DirectionMap<bool>; 2] {
472 let mut bits = self.bits;
473 let mut maps = [DirectionMap::default(); 2];
474 for map in &mut maps {
475 for direction in Direction::ALL {
476 map[direction] = (bits & 1) != 0;
477 bits >>= 1;
478 }
479 }
480 maps
481 }
482
483 pub fn with<F>(self, mapper: F) -> Self
484 where
485 F: FnOnce(DirectionMap<bool>) -> DirectionMap<bool>,
486 {
487 self.packed_with(|maps| [mapper(maps[0]), maps[1]])
488 }
489
490 pub fn packed_with<F>(self, mapper: F) -> Self
491 where
492 F: FnOnce([DirectionMap<bool>; 2]) -> [DirectionMap<bool>; 2],
493 {
494 Self::packed(mapper(self.packed_maps()))
495 }
496
497 pub fn modify<F, T>(&mut self, modifier: F) -> T
498 where
499 F: FnOnce(&mut DirectionMap<bool>) -> T,
500 {
501 self.packed_modify(|maps| modifier(&mut maps[0]))
502 }
503
504 pub fn packed_modify<F, T>(&mut self, modifier: F) -> T
505 where
506 F: FnOnce(&mut [DirectionMap<bool>; 2]) -> T,
507 {
508 let mut maps = self.packed_maps();
509 let output = modifier(&mut maps);
510 *self = Self::packed(maps);
511 output
512 }
513}
514
515impl From<DirectionMap<bool>> for DirectionFlags {
516 fn from(map: DirectionMap<bool>) -> Self {
517 Self::new(map)
518 }
519}
520
521impl From<DirectionFlags> for DirectionMap<bool> {
522 fn from(flags: DirectionFlags) -> Self {
523 flags.map()
524 }
525}
526
527impl From<[DirectionMap<bool>; 2]> for DirectionFlags {
528 fn from(packed_maps: [DirectionMap<bool>; 2]) -> Self {
529 Self::packed(packed_maps)
530 }
531}
532
533impl From<DirectionFlags> for [DirectionMap<bool>; 2] {
534 fn from(flags: DirectionFlags) -> Self {
535 flags.packed_maps()
536 }
537}
538
539#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
540pub struct DirectionVec<C> {
541 pub direction: Direction,
542 pub magnitude: C,
543}
544
545impl<C> DirectionVec<C> {
546 pub fn unit(direction: Direction) -> Self
547 where
548 C: One,
549 {
550 Self { direction, magnitude: C::one() }
551 }
552
553 pub fn as_ref(&self) -> DirectionVec<&C> {
554 DirectionVec { direction: self.direction, magnitude: &self.magnitude }
555 }
556
557 pub fn as_mut(&mut self) -> DirectionVec<&mut C> {
558 DirectionVec {
559 direction: self.direction,
560 magnitude: &mut self.magnitude,
561 }
562 }
563
564 pub fn map<F, C0>(self, mapper: F) -> DirectionVec<C0>
565 where
566 F: FnOnce(C) -> C0,
567 {
568 DirectionVec {
569 direction: self.direction,
570 magnitude: mapper(self.magnitude),
571 }
572 }
573
574 pub fn with_mangitude<C0>(&self, new_magnitude: C0) -> DirectionVec<C0> {
575 self.as_ref().map(|_| new_magnitude)
576 }
577
578 pub fn mov(self, target: CoordPair<C>) -> CoordPair<C>
579 where
580 C: Add<Output = C> + Sub<Output = C>,
581 {
582 match self.direction.axis() {
583 Axis::Y => CoordPair {
584 y: self.direction.order().move_by(self.magnitude, target.y),
585 ..target
586 },
587 Axis::X => CoordPair {
588 x: self.direction.order().move_by(self.magnitude, target.x),
589 ..target
590 },
591 }
592 }
593}
594
595impl<'a, C> DirectionVec<&'a C> {
596 pub fn copied(self) -> DirectionVec<C>
597 where
598 C: Copy,
599 {
600 self.map(|m| *m)
601 }
602
603 pub fn cloned(self) -> DirectionVec<C>
604 where
605 C: Clone,
606 {
607 self.map(Clone::clone)
608 }
609
610 pub fn checked_move(self, target: &CoordPair<C>) -> Option<CoordPair<C>>
611 where
612 C: CheckedAdd + CheckedSub + Clone,
613 {
614 self.checked_move_by_ref(target.as_ref())
615 }
616
617 pub fn checked_move_by_ref(
618 self,
619 target: CoordPair<&C>,
620 ) -> Option<CoordPair<C>>
621 where
622 C: CheckedAdd + CheckedSub + Clone,
623 {
624 match self.direction.axis() {
625 Axis::Y => Some(CoordPair {
626 y: self
627 .direction
628 .order()
629 .checked_move_by(self.magnitude, target.y)?,
630 x: target.x.clone(),
631 }),
632 Axis::X => Some(CoordPair {
633 x: self
634 .direction
635 .order()
636 .checked_move_by(self.magnitude, target.x)?,
637 y: target.y.clone(),
638 }),
639 }
640 }
641
642 pub fn saturating_move(self, target: &CoordPair<C>) -> CoordPair<C>
643 where
644 C: SaturatingAdd + SaturatingSub + Clone,
645 {
646 self.saturating_move_by_ref(target.as_ref())
647 }
648
649 pub fn saturating_move_by_ref(self, target: CoordPair<&C>) -> CoordPair<C>
650 where
651 C: SaturatingAdd + SaturatingSub + Clone,
652 {
653 match self.direction.axis() {
654 Axis::Y => CoordPair {
655 y: self
656 .direction
657 .order()
658 .saturating_move_by(self.magnitude, target.y),
659 x: target.x.clone(),
660 },
661 Axis::X => CoordPair {
662 x: self
663 .direction
664 .order()
665 .saturating_move_by(self.magnitude, target.x),
666 y: target.y.clone(),
667 },
668 }
669 }
670}
671
672impl<'a, C> DirectionVec<&'a mut C> {
673 pub fn copied(self) -> DirectionVec<C>
674 where
675 C: Copy,
676 {
677 self.map(|m| *m)
678 }
679
680 pub fn cloned(self) -> DirectionVec<C>
681 where
682 C: Clone,
683 {
684 self.map(|m| m.clone())
685 }
686
687 pub fn share(self) -> DirectionVec<&'a C> {
688 self.map(|m| &*m)
689 }
690}
691
692#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
693pub enum Diagonal {
694 TopLeft,
695 TopRight,
696 BottomLeft,
697 BottomRight,
698}
699
700impl Diagonal {
701 pub const ALL: [Self; 4] =
702 [Self::TopLeft, Self::TopRight, Self::BottomLeft, Self::BottomRight];
703
704 pub fn new(axes_orders: CoordPair<Order>) -> Self {
705 match axes_orders {
706 CoordPair { y: Order::Backwards, x: Order::Backwards } => {
707 Self::TopLeft
708 },
709 CoordPair { y: Order::Backwards, x: Order::Forwards } => {
710 Self::TopRight
711 },
712 CoordPair { y: Order::Forwards, x: Order::Backwards } => {
713 Self::BottomLeft
714 },
715 CoordPair { y: Order::Forwards, x: Order::Forwards } => {
716 Self::BottomRight
717 },
718 }
719 }
720
721 pub fn axes_orders(self) -> CoordPair<Order> {
722 match self {
723 Self::TopLeft => {
724 CoordPair { y: Order::Backwards, x: Order::Backwards }
725 },
726 Self::TopRight => {
727 CoordPair { y: Order::Backwards, x: Order::Forwards }
728 },
729 Self::BottomLeft => {
730 CoordPair { y: Order::Forwards, x: Order::Backwards }
731 },
732 Self::BottomRight => {
733 CoordPair { y: Order::Forwards, x: Order::Forwards }
734 },
735 }
736 }
737}
738
739impl fmt::Display for Diagonal {
740 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
741 match self {
742 Self::TopLeft => write!(f, "-y -x"),
743 Self::TopRight => write!(f, "-y +x"),
744 Self::BottomLeft => write!(f, "+y -x"),
745 Self::BottomRight => write!(f, "+y +x"),
746 }
747 }
748}
749
750#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
751pub struct DiagonalMap<T> {
752 pub top_left: T,
753 pub top_right: T,
754 pub bottom_left: T,
755 pub bottom_right: T,
756}
757
758impl<T> Index<Diagonal> for DiagonalMap<T> {
759 type Output = T;
760
761 fn index(&self, index: Diagonal) -> &Self::Output {
762 match index {
763 Diagonal::TopLeft => &self.top_left,
764 Diagonal::TopRight => &self.top_right,
765 Diagonal::BottomLeft => &self.bottom_left,
766 Diagonal::BottomRight => &self.bottom_right,
767 }
768 }
769}
770
771impl<T> Index<CoordPair<Order>> for DiagonalMap<T> {
772 type Output = T;
773
774 fn index(&self, index: CoordPair<Order>) -> &Self::Output {
775 &self[Diagonal::new(index)]
776 }
777}
778
779impl<T> IndexMut<Diagonal> for DiagonalMap<T> {
780 fn index_mut(&mut self, index: Diagonal) -> &mut Self::Output {
781 match index {
782 Diagonal::TopLeft => &mut self.top_left,
783 Diagonal::TopRight => &mut self.top_right,
784 Diagonal::BottomLeft => &mut self.bottom_left,
785 Diagonal::BottomRight => &mut self.bottom_right,
786 }
787 }
788}
789
790impl<T> IndexMut<CoordPair<Order>> for DiagonalMap<T> {
791 fn index_mut(&mut self, index: CoordPair<Order>) -> &mut Self::Output {
792 &mut self[Diagonal::new(index)]
793 }
794}