nativeclick/values/
geo.rs1use super::*;
4
5#[derive(Clone, Default, Debug, PartialEq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub struct Point(pub [f64; 2]);
11impl std::hash::Hash for Point {
12 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
13 for x in self.0 {
14 x.to_bits().hash(state);
15 }
16 }
17}
18impl std::ops::Index<u8> for Point {
19 type Output = f64;
20 fn index(&self, index: u8) -> &Self::Output {
21 &self.0[index as usize]
22 }
23}
24impl AsRef<[f64; 2]> for Point {
25 fn as_ref(&self) -> &[f64; 2] {
26 &self.0
27 }
28}
29#[derive(Clone, Hash, Default, Debug, PartialEq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct Ring(pub Vec<Point>);
35#[derive(Clone, Hash, Default, Debug, PartialEq)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub struct Polygon(pub Vec<Ring>);
41#[derive(Clone, Hash, Default, Debug, PartialEq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub struct MultiPolygon(pub Vec<Polygon>);
47
48macro_rules! to_from_sql {
49 ($name:ident) => {
50 impl ToSql for $name {
51 fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
52 Ok(Value::$name(self))
53 }
54 }
55
56 impl FromSql for $name {
57 fn from_sql(type_: &Type, value: Value) -> Result<Self> {
58 if !matches!(type_, Type::$name) {
59 return Err(unexpected_type(type_));
60 }
61 match value {
62 Value::$name(x) => Ok(x),
63 _ => unimplemented!(),
64 }
65 }
66 }
67 };
68}
69
70to_from_sql!(Point);
71to_from_sql!(Ring);
72to_from_sql!(Polygon);
73to_from_sql!(MultiPolygon);
74#[cfg(feature = "geo-types")]
75mod nav_types_conversions {
76 use super::*;
77
78 macro_rules! to_from_sql {
79 ($geo_t:path, $ch_t:ident) => {
80 impl ToSql for $geo_t {
81 fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
82 Ok(Value::$ch_t(self.into()))
83 }
84 }
85 impl FromSql for $geo_t {
86 fn from_sql(type_: &Type, value: Value) -> Result<Self> {
87 if !matches!(type_, Type::$ch_t) {
88 return Err(unexpected_type(type_));
89 }
90 match value {
91 Value::$ch_t(x) => Ok(x.into()),
92 _ => unimplemented!(),
93 }
94 }
95 }
96 };
97 }
98 impl From<Point> for geo_types::Coord {
100 fn from(source: Point) -> Self {
101 Self {
102 x: source[0],
103 y: source[1],
104 }
105 }
106 }
107 impl From<geo_types::Coord> for Point {
108 fn from(source: geo_types::Coord) -> Self {
109 Self([source.x, source.y])
110 }
111 }
112 to_from_sql!(geo_types::Coord, Point);
113
114 impl From<Point> for geo_types::Point {
116 fn from(source: Point) -> Self {
117 geo_types::Point(source.into())
118 }
119 }
120 impl From<geo_types::Point> for Point {
121 fn from(source: geo_types::Point) -> Self {
122 source.0.into()
123 }
124 }
125 to_from_sql!(geo_types::Point, Point);
126 impl From<Ring> for geo_types::LineString {
128 fn from(source: Ring) -> Self {
129 Self(source.0.into_iter().map(geo_types::Coord::from).collect())
130 }
131 }
132 impl From<geo_types::LineString> for Ring {
133 fn from(source: geo_types::LineString) -> Self {
134 Self(source.0.into_iter().map(Point::from).collect())
135 }
136 }
137 to_from_sql!(geo_types::LineString, Ring);
138 impl From<Ring> for geo_types::Polygon {
141 fn from(source: Ring) -> Self {
142 geo_types::Polygon::new(source.0.into(), vec![])
143 }
144 }
145 impl From<geo_types::Polygon> for Polygon {
147 fn from(source: geo_types::Polygon) -> Self {
148 Self(
149 [source.exterior().clone().into()]
150 .into_iter()
151 .chain(
152 source
153 .interiors()
154 .iter()
155 .map(|linestring| Ring::from(linestring.clone())),
156 )
157 .collect(),
158 )
159 }
160 }
161 impl From<Polygon> for geo_types::Polygon {
162 fn from(mut source: Polygon) -> Self {
163 if source.0.is_empty() {
164 return Self::new(geo_types::LineString::new(vec![]), vec![]);
165 }
166 let exterior = source.0.remove(0);
167 geo_types::Polygon::new(
168 exterior.into(),
169 source
170 .0
171 .into_iter()
172 .map(geo_types::LineString::from)
173 .collect(),
174 )
175 }
176 }
177 to_from_sql!(geo_types::Polygon, Polygon);
178 impl From<MultiPolygon> for geo_types::MultiPolygon {
180 fn from(source: MultiPolygon) -> Self {
181 source.0.into_iter().map(geo_types::Polygon::from).collect()
182 }
183 }
184 impl From<geo_types::MultiPolygon> for MultiPolygon {
185 fn from(source: geo_types::MultiPolygon) -> Self {
186 Self(source.into_iter().map(Polygon::from).collect())
187 }
188 }
189 to_from_sql!(geo_types::MultiPolygon, MultiPolygon);
190 #[cfg(test)]
191 #[test]
192 fn roundtrip() {
193 let multipolygon_geo: geo_types::MultiPolygon = geo_types::wkt! {
194 MULTIPOLYGON (((40.0 40.0, 20.0 45.0, 45.0 30.0, 40.0 40.0)),
196 ((20.0 35.0, 10.0 30.0, 10.0 10.0, 30.0 5.0, 45.0 20.0, 20.0 35.0),
197 (30.0 20.0, 20.0 15.0, 20.0 25.0, 30. 20.0)))
198 };
199 let multipolygon = MultiPolygon::from(multipolygon_geo.clone());
200 let multipolygon_geo2 = geo_types::MultiPolygon::from(multipolygon);
201 assert_eq!(multipolygon_geo, multipolygon_geo2);
202 }
203}