1use core::cmp::{Ordering, PartialOrd};
5use core::fmt::Debug;
6use core::hash::Hash;
7use core::marker::PhantomData;
8use core::ops::{Add, AddAssign, Deref, DerefMut, Sub, SubAssign};
9
10use crate::direction::Direction;
11use crate::range::{ComponentRange, LocationRange};
12use crate::vector::{Columns, Component as VecComponent, Rows, Vector, VectorLike};
13
14pub trait Component: Sized + From<isize> + Copy + Debug + Ord + Eq + Hash + Default {
33 type Converse: Component<Converse = Self>;
35
36 type Distance: VecComponent<Point = Self>;
38
39 #[must_use]
51 fn from_location<L: LocationLike>(location: L) -> Self;
52
53 #[must_use]
67 fn combine(self, other: Self::Converse) -> Location;
68
69 #[must_use]
79 fn name() -> &'static str;
80
81 #[must_use]
89 fn value(self) -> isize;
90
91 #[must_use]
101 fn add_distance(self, amount: impl Into<Self::Distance>) -> Self;
102
103 #[must_use]
111 #[inline(always)]
112 fn distance_to(self, target: Self) -> Self::Distance {
113 target.distance_from(self)
114 }
115
116 #[must_use]
124 fn distance_from(self, origin: Self) -> Self::Distance;
125
126 #[must_use]
134 #[inline]
135 fn transpose(self) -> Self::Converse {
136 self.value().into()
137 }
138
139 #[must_use]
147 #[inline]
148 fn span(self, length: Self::Distance) -> ComponentRange<Self> {
149 ComponentRange::span(self, length)
150 }
151
152 #[must_use]
161 #[inline]
162 fn range_to(self, end: Self) -> ComponentRange<Self> {
163 ComponentRange::bounded(self, end)
164 }
165}
166
167macro_rules! make_component {
171 (
172 $Name:ident,
174
175 $Converse:ident,
177
178 $Distance:ident,
180
181 $lower_name:ident,
183
184 $lower_converse:ident,
186
187 $name:literal,
189
190 $test:ident
192 ) => {
193 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
194 #[repr(transparent)]
195 #[doc = "A "]
196 #[doc = $name]
197 #[doc = " component of a [`Location`]. See [`Component`] for details."]
198 pub struct $Name(pub isize);
199
200 impl Add<$Converse> for $Name {
203 type Output = Location;
204
205 #[must_use]
206 #[inline]
207 fn add(self, rhs: $Converse) -> Location {
208 self.combine(rhs)
209 }
210 }
211
212 impl Add<$Distance> for $Name {
213 type Output = Self;
214
215 #[must_use]
216 #[inline]
217 fn add(self, rhs: $Distance) -> Self {
218 $Name(self.0 + rhs.0)
219 }
220 }
221
222 impl AddAssign<$Distance> for $Name {
223 #[inline]
224 fn add_assign(&mut self, rhs: $Distance) {
225 self.0 += rhs.0
226 }
227 }
228
229 impl Sub<$Distance> for $Name {
230 type Output = Self;
231
232 #[must_use]
233 #[inline]
234 fn sub(self, rhs: $Distance) -> Self {
235 $Name(self.0 - rhs.0)
236 }
237 }
238
239 impl SubAssign<$Distance> for $Name {
240 #[inline]
241 fn sub_assign(&mut self, rhs: $Distance) {
242 self.0 -= rhs.0
243 }
244 }
245
246 impl Sub<$Name> for $Name {
248 type Output = $Distance;
249
250 #[must_use]
251 #[inline]
252 fn sub(self, rhs: Self) -> $Distance {
253 $Distance(self.0 - rhs.0)
254 }
255 }
256
257 impl From<isize> for $Name {
258 #[must_use]
259 #[inline]
260 fn from(value: isize) -> Self {
261 $Name(value)
262 }
263 }
264
265 impl LocationLike for ($Name, $Converse) {
266 #[inline]
267 #[must_use]
268 fn $lower_name(&self) -> $Name {
269 self.0
270 }
271
272 #[inline]
273 #[must_use]
274 fn $lower_converse(&self) -> $Converse {
275 self.1
276 }
277
278 #[inline]
279 #[must_use]
280 fn as_location(&self) -> Location {
281 self.0.combine(self.1)
282 }
283 }
284
285 impl Component for $Name {
286 type Converse = $Converse;
287 type Distance = $Distance;
288
289 #[inline]
290 fn from_location<L: LocationLike>(location: L) -> Self {
291 location.$lower_name()
292 }
293
294 #[inline]
295 fn combine(self, other: $Converse) -> Location {
296 Location {
297 $lower_name: self,
298 $lower_converse: other,
299 }
300 }
301
302 #[inline(always)]
303 fn name() -> &'static str {
304 stringify!($lower_name)
305 }
306
307 #[inline]
308 fn add_distance(self, distance: impl Into<$Distance>) -> Self {
309 self + distance.into()
310 }
311
312 #[inline]
313 fn distance_from(self, origin: Self) -> $Distance {
314 self - origin
315 }
316
317 #[inline]
318 fn value(self) -> isize {
319 self.0
320 }
321 }
322
323 #[cfg(test)]
324 mod $test {
325 use crate::location::{$Converse, $Name, Component, Location};
326 use crate::vector::$Distance;
327
328 #[test]
329 fn test_combine_converse() {
330 let base = $Name(3);
331 let converse = $Converse(4);
332
333 assert_eq!(
334 base.combine(converse),
335 Location {
336 $lower_name: base,
337 $lower_converse: converse,
338 }
339 );
340 }
341
342 #[test]
343 fn test_add_converse() {
344 let base = $Name(3);
345 let converse = $Converse(4);
346
347 assert_eq!(base + converse, base.combine(converse));
348 }
349
350 #[test]
351 fn test_add_distance() {
352 let base = $Name(3);
353 let distance = $Distance(4);
354
355 assert_eq!(base + distance, $Name(7));
356 }
357
358 #[test]
359 fn test_add_assign() {
360 let mut base = $Name(3);
361 base += $Distance(4);
362
363 assert_eq!(base, $Name(7));
364 }
365
366 #[test]
367 fn test_sub_distance() {
368 let base = $Name(3);
369 let distance = $Distance(4);
370
371 assert_eq!(base - distance, $Name(-1));
372 }
373
374 #[test]
375 fn test_sub_assign() {
376 let mut base = $Name(3);
377 base -= $Distance(4);
378
379 assert_eq!(base, $Name(-1));
380 }
381
382 #[test]
383 fn test_sub_self() {
384 let origin = $Name(2);
385 let remote = $Name(5);
386
387 assert_eq!(remote - origin, $Distance(3));
388 }
389 }
390 };
391}
392
393make_component! {Row, Column, Rows, row, column, "row", test_row}
394make_component! {Column, Row, Columns, column, row, "column", test_column}
395
396#[derive(Debug, Clone, Copy, Default, Hash, Eq)]
405pub struct Location {
406 pub row: Row,
407 pub column: Column,
408}
409
410impl Location {
411 #[inline]
413 #[must_use]
414 pub fn new(row: impl Into<Row>, column: impl Into<Column>) -> Self {
415 Location {
416 row: row.into(),
417 column: column.into(),
418 }
419 }
420
421 #[must_use]
423 #[inline]
424 pub const fn zero() -> Self {
425 Location {
426 row: Row(0),
427 column: Column(0),
428 }
429 }
430}
431
432pub trait LocationLike: Sized {
435 fn row(&self) -> Row;
437
438 fn column(&self) -> Column;
440
441 #[inline]
443 #[must_use]
444 fn as_location(&self) -> Location {
445 Location {
446 row: self.row(),
447 column: self.column(),
448 }
449 }
450
451 #[inline]
454 #[must_use]
455 fn get_component<T: Component>(&self) -> T {
456 T::from_location(self)
457 }
458
459 #[inline]
468 #[must_use]
469 fn above(&self, distance: impl Into<Rows>) -> Location {
470 Location {
471 row: self.row() - distance.into(),
472 column: self.column(),
473 }
474 }
475
476 #[inline]
485 #[must_use]
486 fn below(&self, distance: impl Into<Rows>) -> Location {
487 Location {
488 row: self.row() + distance.into(),
489 column: self.column(),
490 }
491 }
492
493 #[inline]
502 #[must_use]
503 fn left(&self, distance: impl Into<Columns>) -> Location {
504 Location {
505 row: self.row(),
506 column: self.column() - distance.into(),
507 }
508 }
509
510 #[inline]
519 #[must_use]
520 fn right(&self, distance: impl Into<Columns>) -> Location {
521 Location {
522 row: self.row(),
523 column: self.column() + distance.into(),
524 }
525 }
526
527 #[inline]
529 #[must_use]
530 fn add(&self, distance: impl VectorLike) -> Location {
531 self.as_location() + distance
532 }
533
534 #[inline]
546 #[must_use]
547 fn relative(&self, direction: Direction, distance: isize) -> Location {
548 self.add(direction.sized_vec(distance))
549 }
550
551 #[inline]
564 #[must_use]
565 fn step(&self, direction: Direction) -> Location {
566 self.add(direction.unit_vec())
567 }
568
569 #[inline]
580 #[must_use]
581 fn transpose(&self) -> Location {
582 Location {
583 row: self.column().transpose(),
584 column: self.row().transpose(),
585 }
586 }
587
588 #[inline]
593 #[must_use]
594 fn order_by<Major: Component>(self) -> Ordered<Self, Major> {
595 self.into()
596 }
597
598 #[inline]
617 #[must_use]
618 fn row_ordered(self) -> RowOrdered<Self> {
619 self.order_by()
620 }
621
622 #[inline]
643 #[must_use]
644 fn column_ordered(self) -> ColumnOrdered<Self> {
645 self.order_by()
646 }
647
648 #[inline]
660 #[must_use]
661 fn span_over<C: VecComponent>(
662 self,
663 distance: C,
664 ) -> LocationRange<<C::Point as Component>::Converse> {
665 LocationRange::rooted(self.as_location(), distance)
666 }
667
668 #[inline]
681 #[must_use]
682 fn range_to<C: Component>(self, end: C) -> LocationRange<C::Converse> {
683 LocationRange::bounded(self.get_component(), self.get_component(), end)
684 }
685}
686
687impl LocationLike for Location {
688 #[inline(always)]
689 #[must_use]
690 fn row(&self) -> Row {
691 self.row
692 }
693
694 #[inline(always)]
695 #[must_use]
696 fn column(&self) -> Column {
697 self.column
698 }
699
700 #[inline(always)]
701 #[must_use]
702 fn as_location(&self) -> Location {
703 *self
704 }
705}
706
707impl<T: LocationLike> LocationLike for &T {
708 #[inline(always)]
709 #[must_use]
710 fn row(&self) -> Row {
711 T::row(self)
712 }
713
714 #[inline(always)]
715 #[must_use]
716 fn column(&self) -> Column {
717 T::column(self)
718 }
719
720 #[inline(always)]
721 #[must_use]
722 fn as_location(&self) -> Location {
723 T::as_location(self)
724 }
725}
726
727impl<T: VectorLike> Add<T> for Location {
728 type Output = Location;
729
730 #[inline]
731 #[must_use]
732 fn add(self, rhs: T) -> Location {
733 let rhs = rhs.as_vector();
734 Location {
735 row: self.row + rhs.rows,
736 column: self.column + rhs.columns,
737 }
738 }
739}
740
741#[cfg(test)]
742#[test]
743fn test_add() {
744 use crate::direction::*;
745
746 assert_eq!(
747 Location::new(3, 5) + Vector::new(-1, 6),
748 Location::new(2, 11)
749 );
750 assert_eq!(Location::zero() + Rows(5), Location::new(5, 0));
751 assert_eq!(Location::zero() + Columns(-2), Location::new(0, -2));
752 assert_eq!(Location::zero() + (2, 3), Location::new(2, 3));
753 assert_eq!(
754 Location::zero() + (Rows(1), Columns(1)),
755 Location::new(1, 1)
756 );
757 assert_eq!(
758 Location::zero() + (Columns(4), Rows(4)),
759 Location::new(4, 4)
760 );
761 assert_eq!(Location::zero() + Up, Location::new(-1, 0));
762}
763
764impl<T: VectorLike> AddAssign<T> for Location {
765 #[inline]
766 fn add_assign(&mut self, rhs: T) {
767 let rhs = rhs.as_vector();
768
769 self.row += rhs.rows;
770 self.column += rhs.columns;
771 }
772}
773
774#[cfg(test)]
775#[test]
776fn test_add_assign() {
777 let mut loc = Location::zero();
778
779 loc += Vector::new(-2, 5);
780 assert_eq!(loc, Location::new(-2, 5));
781
782 loc += Rows(4);
783 assert_eq!(loc, Location::new(2, 5));
784
785 loc += Columns(5);
786 assert_eq!(loc, Location::new(2, 10));
787}
788
789impl<T: VectorLike> Sub<T> for Location {
790 type Output = Location;
791
792 #[inline]
793 #[must_use]
794 fn sub(self, rhs: T) -> Location {
795 let rhs = rhs.as_vector();
796
797 Location {
798 row: self.row - rhs.rows,
799 column: self.column - rhs.columns,
800 }
801 }
802}
803
804#[cfg(test)]
805#[test]
806fn test_sub() {
807 assert_eq!(
808 Location::new(3, 5) - Vector::new(-1, 6),
809 Location::new(4, -1)
810 );
811 assert_eq!(Location::zero() - Rows(5), Location::new(-5, 0));
812 assert_eq!(Location::zero() - Columns(-2), Location::new(0, 2));
813 assert_eq!(Location::zero() - (2, 3), Location::new(-2, -3));
814 assert_eq!(
815 Location::zero() - (Rows(1), Columns(1)),
816 Location::new(-1, -1)
817 );
818 assert_eq!(
819 Location::zero() - (Columns(4), Rows(4)),
820 Location::new(-4, -4)
821 );
822}
823
824impl<T: VectorLike> SubAssign<T> for Location {
825 #[inline]
826 fn sub_assign(&mut self, rhs: T) {
827 let rhs = rhs.as_vector();
828 self.row -= rhs.rows;
829 self.column -= rhs.columns;
830 }
831}
832
833#[cfg(test)]
834#[test]
835fn test_sub_assign() {
836 let mut loc = Location::zero();
837
838 loc -= Vector::new(-2, 5);
839 assert_eq!(loc, Location::new(2, -5));
840
841 loc -= Rows(4);
842 assert_eq!(loc, Location::new(-2, -5));
843
844 loc -= Columns(5);
845 assert_eq!(loc, Location::new(-2, -10));
846}
847
848impl Sub<Location> for Location {
854 type Output = Vector;
855
856 #[inline]
857 #[must_use]
858 fn sub(self, rhs: Location) -> Vector {
859 Vector {
860 rows: self.row - rhs.row,
861 columns: self.column - rhs.column,
862 }
863 }
864}
865
866impl Sub<(Row, Column)> for Location {
867 type Output = Vector;
868
869 #[inline]
870 #[must_use]
871 fn sub(self, (row, column): (Row, Column)) -> Vector {
872 Vector {
873 rows: self.row - row,
874 columns: self.column - column,
875 }
876 }
877}
878
879impl Sub<(Column, Row)> for Location {
880 type Output = Vector;
881
882 #[inline]
883 #[must_use]
884 fn sub(self, (column, row): (Column, Row)) -> Vector {
885 Vector {
886 rows: self.row - row,
887 columns: self.column - column,
888 }
889 }
890}
891
892#[cfg(test)]
895#[test]
896fn test_sub_self() {
897 let loc1 = Location::new(4, 5);
898 let loc2 = Location::new(1, 1);
899 assert_eq!(loc1 - loc2, Vector::new(3, 4));
900}
901
902#[cfg(test)]
903#[test]
904fn test_sub_self_tuple() {
905 let loc1 = Location::new(4, 5);
906 let loc2 = (Row(1), Column(2));
907 assert_eq!(loc1 - loc2, Vector::new(3, 3));
908}
909
910#[cfg(test)]
911#[test]
912fn test_sub_self_reverse_tuple() {
913 let loc1 = Location::new(4, 5);
914 let loc2 = (Column(2), Row(1));
915 assert_eq!(loc1 - loc2, Vector::new(3, 3));
916}
917
918impl<T: LocationLike> PartialEq<T> for Location {
919 #[must_use]
920 #[inline]
921 fn eq(&self, rhs: &T) -> bool {
922 self.row == rhs.row() && self.column == rhs.column()
923 }
924}
925
926impl<T: LocationLike> PartialOrd<T> for Location {
945 #[must_use]
946 fn partial_cmp(&self, rhs: &T) -> Option<Ordering> {
947 match (self.row.cmp(&rhs.row()), self.column.cmp(&rhs.column())) {
948 (Ordering::Greater, Ordering::Less) | (Ordering::Less, Ordering::Greater) => None,
949 (o1, o2) => Some(o1.then(o2)),
950 }
951 }
952}
953
954#[cfg(test)]
955mod partial_ord_tests {
956 use crate::prelude::{Location, LocationLike};
957 use crate::shorthand::{C, L, R};
958 use core::cmp::Ordering;
959
960 const ZERO: Location = Location::zero();
961
962 #[test]
963 fn test_eq() {
964 assert_eq!(L(3, 4), (R(3), C(4)));
965 assert_eq!(L(3, 4), (C(4), R(3)));
966 assert_eq!(L(3, 4), L(3, 4));
967 assert_eq!(L(3, 4), (3, 4));
968 }
969
970 #[test]
971 fn test_orderliness() {
972 assert_eq!(ZERO.partial_cmp(&ZERO.above(1)), Some(Ordering::Greater));
973 assert_eq!(ZERO.partial_cmp(&ZERO.left(1)), Some(Ordering::Greater));
974 assert_eq!(ZERO.partial_cmp(&(ZERO - (1, 1))), Some(Ordering::Greater));
975
976 assert_eq!(ZERO.partial_cmp(&ZERO.below(1)), Some(Ordering::Less));
977 assert_eq!(ZERO.partial_cmp(&ZERO.right(1)), Some(Ordering::Less));
978 assert_eq!(ZERO.partial_cmp(&(ZERO + (1, 1))), Some(Ordering::Less));
979
980 assert_eq!(ZERO.partial_cmp(&(ZERO + (-1, 1))), None);
981 assert_eq!(ZERO.partial_cmp(&(ZERO - (-1, 1))), None);
982
983 assert_eq!(ZERO.partial_cmp(&ZERO), Some(Ordering::Equal));
984 }
985
986 #[test]
987 fn test_bad_diagonal() {
988 for location in &[L(1, -1), L(-1, 1)] {
989 assert!(!(ZERO < *location));
990 assert!(!(ZERO > *location));
991 assert!(!(ZERO <= *location));
992 assert!(!(ZERO >= *location));
993 }
994 }
995}
996
997impl LocationLike for (isize, isize) {
999 #[inline]
1000 #[must_use]
1001 fn row(&self) -> Row {
1002 Row(self.0)
1003 }
1004
1005 #[inline]
1006 #[must_use]
1007 fn column(&self) -> Column {
1008 Column(self.1)
1009 }
1010
1011 #[inline]
1012 #[must_use]
1013 fn as_location(&self) -> Location {
1014 Location::new(self.0, self.1)
1015 }
1016}
1017
1018#[derive(Debug, Clone, Copy, Default, Hash)]
1024pub struct Ordered<L: LocationLike, Major: Component> {
1025 pub location: L,
1026 phantom: PhantomData<Major>,
1027}
1028
1029impl<L: LocationLike, M: Component> Ordered<L, M> {
1030 #[inline]
1031 #[must_use]
1032 pub fn new(location: L) -> Self {
1033 Self {
1034 location,
1035 phantom: PhantomData,
1036 }
1037 }
1038}
1039
1040impl<L: LocationLike, M: Component> From<L> for Ordered<L, M> {
1041 #[inline]
1042 #[must_use]
1043 fn from(location: L) -> Self {
1044 Self::new(location)
1045 }
1046}
1047
1048impl<L: LocationLike, M: Component> AsRef<L> for Ordered<L, M> {
1049 #[inline]
1050 #[must_use]
1051 fn as_ref(&self) -> &L {
1052 &self.location
1053 }
1054}
1055
1056impl<L: LocationLike, M: Component> AsMut<L> for Ordered<L, M> {
1057 #[inline]
1058 #[must_use]
1059 fn as_mut(&mut self) -> &mut L {
1060 &mut self.location
1061 }
1062}
1063
1064impl<L: LocationLike, M: Component> Deref for Ordered<L, M> {
1065 type Target = L;
1066
1067 #[inline]
1068 #[must_use]
1069 fn deref(&self) -> &L {
1070 &self.location
1071 }
1072}
1073
1074impl<L: LocationLike, M: Component> DerefMut for Ordered<L, M> {
1075 #[inline]
1076 #[must_use]
1077 fn deref_mut(&mut self) -> &mut L {
1078 &mut self.location
1079 }
1080}
1081
1082impl<L: LocationLike, M: Component> LocationLike for Ordered<L, M> {
1083 #[inline]
1084 #[must_use]
1085 fn row(&self) -> Row {
1086 self.location.row()
1087 }
1088
1089 #[inline]
1090 #[must_use]
1091 fn column(&self) -> Column {
1092 self.location.column()
1093 }
1094
1095 #[inline]
1096 #[must_use]
1097 fn as_location(&self) -> Location {
1098 self.location.as_location()
1099 }
1100}
1101
1102impl<L: LocationLike, M: Component, R: LocationLike> PartialEq<R> for Ordered<L, M> {
1103 #[inline]
1104 #[must_use]
1105 fn eq(&self, rhs: &R) -> bool {
1106 self.as_location() == rhs.as_location()
1107 }
1108}
1109
1110impl<L: LocationLike, M: Component> Eq for Ordered<L, M> {}
1111
1112impl<L: LocationLike, M: Component> PartialOrd for Ordered<L, M> {
1113 #[inline]
1114 #[must_use]
1115 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
1116 Some(self.cmp(rhs))
1117 }
1118
1119 #[inline]
1120 #[must_use]
1121 fn lt(&self, rhs: &Self) -> bool {
1122 self.cmp(rhs) == Ordering::Less
1123 }
1124
1125 #[inline]
1126 #[must_use]
1127 fn le(&self, rhs: &Self) -> bool {
1128 self.cmp(rhs) != Ordering::Greater
1129 }
1130
1131 #[inline]
1132 #[must_use]
1133 fn gt(&self, rhs: &Self) -> bool {
1134 self.cmp(rhs) == Ordering::Greater
1135 }
1136
1137 #[inline]
1138 #[must_use]
1139 fn ge(&self, rhs: &Self) -> bool {
1140 self.cmp(rhs) != Ordering::Less
1141 }
1142}
1143
1144impl<L: LocationLike, M: Component> Ord for Ordered<L, M> {
1145 fn cmp(&self, rhs: &Self) -> Ordering {
1146 M::from_location(self)
1147 .cmp(&M::from_location(rhs))
1148 .then_with(move || {
1149 M::Converse::from_location(self).cmp(&M::Converse::from_location(rhs))
1150 })
1151 }
1152}
1153
1154pub type RowOrdered<L> = Ordered<L, Row>;
1156
1157pub type ColumnOrdered<L> = Ordered<L, Column>;
1159
1160pub type RowOrderedLocation = RowOrdered<Location>;
1162
1163pub type ColumnOrderedLocation = ColumnOrdered<Location>;