1use std::fmt;
4
5use serde::de::{
6 Deserialize,
7 Deserializer,
8 Error,
9 IgnoredAny,
10 MapAccess,
11 SeqAccess,
12 Unexpected,
13 Visitor,
14};
15
16use util::CowStr;
17
18#[derive(Clone, Debug, PartialEq)]
22pub enum Geometry {
23 Point(Position),
24 MultiPoint(Vec<Position>),
25 LineString(LineString),
26 MultiLineString(Vec<LineString>),
27 Polygon(Polygon),
28 MultiPolygon(Vec<Polygon>),
29 }
31
32#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
33pub struct Position(
34 pub f64,
36 pub f64,
38 );
40
41pub type LineString = Vec<Position>;
42pub type Polygon = Vec<LinearRing>;
43pub type LinearRing = LineString;
44
45impl<'x> Deserialize<'x> for Geometry {
46 fn deserialize<D: Deserializer<'x>>(d: D) -> Result<Self, D::Error> {
47 d.deserialize_map(GeometryVisitor)
48 }
49}
50
51struct GeometryVisitor;
52
53enum Coordinates {
54 F64(f64),
55 Dim0(Position), Dim1(Vec<Position>), Dim2(Vec<Vec<Position>>), Dim3(Vec<Vec<Vec<Position>>>), }
60
61struct CoordinatesVisitor;
62
63impl<'x> Visitor<'x> for GeometryVisitor {
64 type Value = Geometry;
65
66 fn visit_map<V: MapAccess<'x>>(self, mut v: V)
67 -> Result<Geometry, V::Error>
68 {
69 use self::Geometry::*;
70
71 let mut c = None;
72
73 macro_rules! end {
74 () => {
75 while v.next_entry::<IgnoredAny, IgnoredAny>()?.is_some() {}
76 };
77 }
78
79 while let Some(k) = v.next_key::<String>()? {
80 match &*k {
81 "type" => {
82 let t = v.next_value::<CowStr>()?;
83 macro_rules! match_type {
84 ($C:ident, $($($V:ident($typ:expr))|* => $D:ident,)*) =>
85 {{
86 const EXPECTED: &[&str] = &[$($($typ),*),*];
87 match &*t {
88 $($($typ => match c {
89 Some($C::$D(val)) => {
90 end!();
91 return Ok($V(val));
92 },
93 None => {
94 while let Some(k)
95 = v.next_key::<CowStr>()?
96 {
97 if "coordinates" == &*k {
98 let c = v.next_value()?;
99 end!();
100 return Ok($V(c));
101 } else {
102 v.next_value::<IgnoredAny>()?;
103 }
104 }
105 return Err(V::Error::missing_field(
106 "coordinates"
107 ));
108 },
109 _ => return Err(V::Error::custom(
110 "invalid coordinates type"
111 )),
112 },)*)*
113 s => return Err(
114 V::Error::unknown_variant(s, EXPECTED)
115 ),
116 }
117 }};
118 }
119 match_type! {
120 Coordinates,
121 Point("Point") => Dim0,
122 MultiPoint("MultiPoint") | LineString("LineString")
123 => Dim1,
124 MultiLineString("MultiLineString") | Polygon("Polygon")
125 => Dim2,
126 MultiPolygon("MultiPolygon") => Dim3,
127 }
128 },
129 "coordinates" => c = Some(v.next_value()?),
130 _ => { v.next_value::<IgnoredAny>()?; },
131 }
132 }
133
134 Err(V::Error::missing_field("type"))
135 }
136
137 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 write!(f, "a map with `type` and `coordinate` fields")
139 }
140}
141
142impl<'x> Deserialize<'x> for Coordinates {
143 fn deserialize<D: Deserializer<'x>>(d: D)
144 -> Result<Self, D::Error>
145 {
146 d.deserialize_any(CoordinatesVisitor)
147 }
148}
149
150impl<'x> Visitor<'x> for CoordinatesVisitor {
151 type Value = Coordinates;
152
153 fn visit_f64<E>(self, v: f64) -> Result<Coordinates, E> {
154 Ok(Coordinates::F64(v))
155 }
156
157 fn visit_i64<E>(self, v: i64) -> Result<Coordinates, E> {
158 Ok(Coordinates::F64(v as _))
159 }
160
161 fn visit_u64<E>(self, v: u64) -> Result<Coordinates, E> {
162 Ok(Coordinates::F64(v as _))
163 }
164
165 fn visit_seq<V: SeqAccess<'x>>(self, mut v: V)
166 -> Result<Coordinates, V::Error>
167 {
168 macro_rules! match_val {
169 (
170 $C:ident,
171 $($V:ident => $R:ident,)*
172 ) => {
173 match v.next_element()? {
174 Some($C::F64(v1)) => {
175 let v2 = match v.next_element()? {
176 Some(val) => val,
177 None => return Err(
178 V::Error::invalid_length(1, &self)
179 ),
180 };
181 while v.next_element::<IgnoredAny>()?.is_some() {}
182 Ok($C::Dim0(Position(v1, v2)))
183 },
184 $(Some($C::$V(val)) => {
185 let mut ret = v.size_hint()
186 .map(Vec::with_capacity)
187 .unwrap_or_else(Vec::new);
188 ret.push(val);
189 while let Some(val) = v.next_element()? {
190 ret.push(val);
191 }
192 Ok($C::$R(ret))
193 },)*
194 Some($C::Dim3(_)) => Err(
195 V::Error::invalid_type(Unexpected::Seq, &self)
196 ),
197 None => Ok($C::Dim1(Vec::new())),
198 }
199 };
200 }
201
202 match_val! {
203 Coordinates,
204 Dim0 => Dim1,
205 Dim1 => Dim2,
206 Dim2 => Dim3,
207 }
208 }
209
210 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
211 write!(f,
212 "a floating point number \
213 or an array of floating point number with a depth of 4 or lower"
214 )
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use json;
221 use super::*;
222
223 #[test]
224 fn deserialize_pass() {
225 macro_rules! assert_deserialize_to {
226 ($typ:ident($($inner:tt)*), $c:expr) => {{
227 let geo = Geometry::$typ($($inner)*);
228 let c = format!("\"coordinates\":{}", $c);
229 let t = format!("\"type\":\"{}\"", stringify!($typ));
230 assert_eq!(geo, json::from_str(&format!(
231 "{{{},{}}}", c, t
232 )).unwrap());
233 assert_eq!(geo, json::from_str(&format!
234 ("{{{},{}}}", t, c
235 )).unwrap());
236 assert_eq!(geo, json::from_str(&format!(
237 "{{\"1\":0,{},\"2\":[],{},\"3\":null}}", c, t
238 )).unwrap());
239 assert_eq!(geo, json::from_str(&format!(
240 "{{\"1\":0,{},\"2\":[],{},\"3\":null}}", t, c
241 )).unwrap());
242 }};
243 }
244
245 assert_deserialize_to!(
246 Point(Position(-75.14310264, 40.05701649)),
247 "[-75.14310264,40.05701649]"
248 );
249 assert_deserialize_to!(
250 Polygon(vec![vec![
251 Position(2.2241006,48.8155414),
252 Position(2.4699099,48.8155414),
253 Position(2.4699099,48.9021461),
254 Position(2.2241006,48.9021461),
255 ]]),
256 "[[
257 [2.2241006,48.8155414],
258 [2.4699099,48.8155414],
259 [2.4699099,48.9021461],
260 [2.2241006,48.9021461]
261 ]]"
262 );
263 }
264
265 #[test]
266 fn deserialize_fail() {
267 macro_rules! assert_fail {
268 ($json:expr) => {{
269 json::from_str::<::serde::de::IgnoredAny>($json).unwrap();
270 json::from_str::<Geometry>($json).unwrap_err();
271 }};
272 }
273
274 assert_fail!("{}");
275 assert_fail!("[0,1]");
276 assert_fail!("{\"coordinates\":[1],\"type\":\"Point\"}");
277 assert_fail!("{\"coordinates\":[1,2],\"type\":\"MultiPoint\"}");
278 assert_fail!("{\"coordinates\":[[[[[0,0]]]]],\"type\":\"MultiPolygon\"}");
279 assert_fail!("{\"coordinates\":[],\"type\":\"Foo\"}");
280 }
281}