geo_traits/coord.rs
1use std::marker::PhantomData;
2
3#[cfg(feature = "geo-types")]
4use geo_types::{Coord, CoordNum};
5
6use crate::Dimensions;
7
8/// A trait for accessing data from a generic Coord.
9///
10/// Refer to [geo_types::Coord] for information about semantics and validity.
11pub trait CoordTrait {
12 /// The coordinate type of this geometry
13 type T;
14
15 /// Dimensions of the coordinate tuple
16 fn dim(&self) -> Dimensions;
17
18 /// Access the n'th (0-based) element of the CoordinateTuple.
19 /// Returns `None` if `n >= DIMENSION`.
20 ///
21 /// See also [`nth_or_panic()`](Self::nth_or_panic) and [`nth_unchecked()`](Self::nth_unchecked).
22 ///
23 /// # Panics
24 ///
25 /// This method may panic if [`dim()`](Self::dim) does not correspond to
26 /// the actual number of dimensions in this coordinate.
27 fn nth(&self, n: usize) -> Option<Self::T> {
28 if n < self.dim().size() {
29 Some(self.nth_or_panic(n))
30 } else {
31 None
32 }
33 }
34
35 /// x component of this coord.
36 fn x(&self) -> Self::T;
37
38 /// y component of this coord.
39 fn y(&self) -> Self::T;
40
41 /// Returns a tuple that contains the x/horizontal & y/vertical component of the coord.
42 fn x_y(&self) -> (Self::T, Self::T) {
43 (self.x(), self.y())
44 }
45
46 /// Access the n'th (0-based) element of the CoordinateTuple.
47 /// May panic if n >= DIMENSION.
48 /// See also [`nth()`](Self::nth).
49 fn nth_or_panic(&self, n: usize) -> Self::T;
50
51 /// Access the n'th (0-based) element of the CoordinateTuple.
52 /// May panic if n >= DIMENSION.
53 ///
54 /// See also [`nth()`](Self::nth), [`nth_or_panic()`](Self::nth_or_panic).
55 ///
56 /// You might want to override the default implementation of this method
57 /// if you can provide a more efficient implementation.
58 ///
59 /// # Safety
60 ///
61 /// Though it may panic, the default implementation actually is safe. However, implementors
62 /// are allowed to implement this method themselves with an unsafe implementation. See the
63 /// individual implementations for more information on their own Safety considerations.
64 unsafe fn nth_unchecked(&self, n: usize) -> Self::T {
65 self.nth_or_panic(n)
66 }
67}
68
69#[cfg(feature = "geo-types")]
70impl<T: CoordNum> CoordTrait for Coord<T> {
71 type T = T;
72
73 fn nth_or_panic(&self, n: usize) -> Self::T {
74 match n {
75 0 => self.x(),
76 1 => self.y(),
77 _ => panic!("Coord only supports 2 dimensions"),
78 }
79 }
80
81 fn dim(&self) -> Dimensions {
82 Dimensions::Xy
83 }
84
85 fn x(&self) -> Self::T {
86 self.x
87 }
88
89 fn y(&self) -> Self::T {
90 self.y
91 }
92}
93
94#[cfg(feature = "geo-types")]
95impl<T: CoordNum> CoordTrait for &Coord<T> {
96 type T = T;
97
98 fn nth_or_panic(&self, n: usize) -> Self::T {
99 match n {
100 0 => self.x(),
101 1 => self.y(),
102 _ => panic!("Coord only supports 2 dimensions"),
103 }
104 }
105
106 fn dim(&self) -> Dimensions {
107 Dimensions::Xy
108 }
109
110 fn x(&self) -> Self::T {
111 self.x
112 }
113
114 fn y(&self) -> Self::T {
115 self.y
116 }
117}
118
119impl<T: Copy> CoordTrait for (T, T) {
120 type T = T;
121
122 fn nth_or_panic(&self, n: usize) -> Self::T {
123 match n {
124 0 => self.x(),
125 1 => self.y(),
126 _ => panic!("(T, T) only supports 2 dimensions"),
127 }
128 }
129
130 fn dim(&self) -> Dimensions {
131 Dimensions::Xy
132 }
133
134 fn x(&self) -> Self::T {
135 self.0
136 }
137
138 fn y(&self) -> Self::T {
139 self.1
140 }
141}
142
143/// An empty struct that implements [CoordTrait].
144///
145/// This can be used as the `CoordType` of the `GeometryTrait` by implementations that don't have a
146/// Coord concept
147pub struct UnimplementedCoord<T>(PhantomData<T>);
148
149impl<T> CoordTrait for UnimplementedCoord<T> {
150 type T = T;
151
152 fn dim(&self) -> Dimensions {
153 unimplemented!()
154 }
155
156 fn nth_or_panic(&self, _n: usize) -> Self::T {
157 unimplemented!()
158 }
159
160 fn x(&self) -> Self::T {
161 unimplemented!()
162 }
163
164 fn y(&self) -> Self::T {
165 unimplemented!()
166 }
167}