1use crate::errors::{Error, Result};
16use crate::{Feature, FeatureCollection, Geometry};
17use crate::{JsonObject, JsonValue};
18use serde::{Deserialize, Deserializer, Serialize, Serializer};
19use std::convert::TryFrom;
20use std::fmt;
21use std::iter::FromIterator;
22use std::str::FromStr;
23
24#[derive(Clone, Debug, PartialEq)]
47pub enum GeoJson {
48 Geometry(Geometry),
49 Feature(Feature),
50 FeatureCollection(FeatureCollection),
51}
52
53impl<'a> From<&'a GeoJson> for JsonObject {
54 fn from(geojson: &'a GeoJson) -> JsonObject {
55 match *geojson {
56 GeoJson::Geometry(ref geometry) => geometry.into(),
57 GeoJson::Feature(ref feature) => feature.into(),
58 GeoJson::FeatureCollection(ref fc) => fc.into(),
59 }
60 }
61}
62
63impl From<GeoJson> for JsonValue {
64 fn from(geojson: GeoJson) -> JsonValue {
65 match geojson {
66 GeoJson::Geometry(geometry) => JsonValue::Object(JsonObject::from(&geometry)),
67 GeoJson::Feature(feature) => JsonValue::Object(JsonObject::from(&feature)),
68 GeoJson::FeatureCollection(fc) => JsonValue::Object(JsonObject::from(&fc)),
69 }
70 }
71}
72
73impl<G: Into<Geometry>> From<G> for GeoJson {
74 fn from(geometry: G) -> Self {
75 GeoJson::Geometry(geometry.into())
76 }
77}
78
79impl<G: Into<Geometry>> FromIterator<G> for GeoJson {
80 fn from_iter<I: IntoIterator<Item = G>>(iter: I) -> Self {
81 use crate::Value;
82 let geometries = iter.into_iter().map(|g| g.into()).collect();
83 let collection = Value::GeometryCollection(geometries);
84 GeoJson::Geometry(Geometry::new(collection))
85 }
86}
87
88impl From<Feature> for GeoJson {
89 fn from(feature: Feature) -> Self {
90 GeoJson::Feature(feature)
91 }
92}
93
94impl From<FeatureCollection> for GeoJson {
95 fn from(feature_collection: FeatureCollection) -> GeoJson {
96 GeoJson::FeatureCollection(feature_collection)
97 }
98}
99
100impl From<Vec<Feature>> for GeoJson {
101 fn from(features: Vec<Feature>) -> GeoJson {
102 GeoJson::from(features.into_iter().collect::<FeatureCollection>())
103 }
104}
105
106impl TryFrom<GeoJson> for Geometry {
107 type Error = Error;
108 fn try_from(value: GeoJson) -> Result<Self> {
109 match value {
110 GeoJson::Geometry(g) => Ok(g),
111 GeoJson::Feature(_) => Err(Error::ExpectedType {
112 expected: "Geometry".to_string(),
113 actual: "Feature".to_string(),
114 }),
115 GeoJson::FeatureCollection(_) => Err(Error::ExpectedType {
116 expected: "Geometry".to_string(),
117 actual: "FeatureCollection".to_string(),
118 }),
119 }
120 }
121}
122
123impl TryFrom<GeoJson> for Feature {
124 type Error = Error;
125 fn try_from(value: GeoJson) -> Result<Self> {
126 match value {
127 GeoJson::Geometry(_) => Err(Error::ExpectedType {
128 expected: "Feature".to_string(),
129 actual: "Geometry".to_string(),
130 }),
131 GeoJson::Feature(f) => Ok(f),
132 GeoJson::FeatureCollection(_) => Err(Error::ExpectedType {
133 expected: "Feature".to_string(),
134 actual: "FeatureCollection".to_string(),
135 }),
136 }
137 }
138}
139
140impl TryFrom<GeoJson> for FeatureCollection {
141 type Error = Error;
142 fn try_from(value: GeoJson) -> Result<Self> {
143 match value {
144 GeoJson::Geometry(_) => Err(Error::ExpectedType {
145 expected: "FeatureCollection".to_string(),
146 actual: "Geometry".to_string(),
147 }),
148 GeoJson::Feature(_) => Err(Error::ExpectedType {
149 expected: "FeatureCollection".to_string(),
150 actual: "Feature".to_string(),
151 }),
152 GeoJson::FeatureCollection(f) => Ok(f),
153 }
154 }
155}
156
157impl GeoJson {
158 pub fn from_json_object(object: JsonObject) -> Result<Self> {
159 Self::try_from(object)
160 }
161
162 pub fn from_json_value(value: JsonValue) -> Result<Self> {
195 Self::try_from(value)
196 }
197
198 pub fn to_json_value(self) -> JsonValue {
226 JsonValue::from(self)
227 }
228
229 pub fn from_reader<R>(rdr: R) -> serde_json::Result<Self>
231 where
232 R: std::io::Read,
233 {
234 serde_json::from_reader(rdr)
235 }
236
237 pub fn to_string_pretty(self) -> Result<String> {
239 ::serde_json::to_string_pretty(&self)
240 .map_err(Error::MalformedJson)
241 .map(|s| s.to_string())
242 }
243}
244
245impl TryFrom<JsonObject> for GeoJson {
246 type Error = Error;
247
248 fn try_from(object: JsonObject) -> Result<Self> {
249 let type_ = match object.get("type") {
250 Some(JsonValue::String(t)) => Type::from_str(t),
251 _ => return Err(Error::GeometryUnknownType("type".to_owned())),
252 };
253 let type_ = type_.ok_or(Error::EmptyType)?;
254 match type_ {
255 Type::Feature => Feature::try_from(object).map(GeoJson::Feature),
256 Type::FeatureCollection => {
257 FeatureCollection::try_from(object).map(GeoJson::FeatureCollection)
258 }
259 _ => Geometry::try_from(object).map(GeoJson::Geometry),
260 }
261 }
262}
263
264impl TryFrom<JsonValue> for GeoJson {
265 type Error = Error;
266
267 fn try_from(value: JsonValue) -> Result<Self> {
268 if let JsonValue::Object(obj) = value {
269 Self::try_from(obj)
270 } else {
271 Err(Error::GeoJsonExpectedObject(value))
272 }
273 }
274}
275
276#[derive(PartialEq, Clone, Copy)]
277enum Type {
278 Point,
279 MultiPoint,
280 LineString,
281 MultiLineString,
282 Polygon,
283 MultiPolygon,
284 GeometryCollection,
285 Feature,
286 FeatureCollection,
287}
288
289impl Type {
290 fn from_str(s: &str) -> Option<Self> {
291 match s {
292 "Point" => Some(Type::Point),
293 "MultiPoint" => Some(Type::MultiPoint),
294 "LineString" => Some(Type::LineString),
295 "MultiLineString" => Some(Type::MultiLineString),
296 "Polygon" => Some(Type::Polygon),
297 "MultiPolygon" => Some(Type::MultiPolygon),
298 "GeometryCollection" => Some(Type::GeometryCollection),
299 "Feature" => Some(Type::Feature),
300 "FeatureCollection" => Some(Type::FeatureCollection),
301 _ => None,
302 }
303 }
304}
305
306impl Serialize for GeoJson {
307 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
308 where
309 S: Serializer,
310 {
311 match self {
312 GeoJson::Geometry(ref geometry) => geometry.serialize(serializer),
313 GeoJson::Feature(ref feature) => feature.serialize(serializer),
314 GeoJson::FeatureCollection(ref fc) => fc.serialize(serializer),
315 }
316 }
317}
318
319impl<'de> Deserialize<'de> for GeoJson {
320 fn deserialize<D>(deserializer: D) -> std::result::Result<GeoJson, D::Error>
321 where
322 D: Deserializer<'de>,
323 {
324 use serde::de::Error as SerdeError;
325
326 let val = JsonObject::deserialize(deserializer)?;
327
328 GeoJson::from_json_object(val).map_err(|e| D::Error::custom(e.to_string()))
329 }
330}
331
332impl FromStr for GeoJson {
362 type Err = Error;
363
364 fn from_str(s: &str) -> Result<Self> {
365 let object = get_object(s)?;
366
367 GeoJson::from_json_object(object)
368 }
369}
370
371fn get_object(s: &str) -> Result<JsonObject> {
372 match ::serde_json::from_str(s)? {
373 JsonValue::Object(object) => Ok(object),
374 other => Err(Error::ExpectedObjectValue(other)),
375 }
376}
377
378impl fmt::Display for GeoJson {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 ::serde_json::to_string(self)
381 .map_err(|_| fmt::Error)
382 .and_then(|s| f.write_str(&s))
383 }
384}
385
386impl fmt::Display for Feature {
387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388 ::serde_json::to_string(self)
389 .map_err(|_| fmt::Error)
390 .and_then(|s| f.write_str(&s))
391 }
392}
393
394impl fmt::Display for Geometry {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 ::serde_json::to_string(self)
397 .map_err(|_| fmt::Error)
398 .and_then(|s| f.write_str(&s))
399 }
400}
401
402impl fmt::Display for FeatureCollection {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 ::serde_json::to_string(self)
405 .map_err(|_| fmt::Error)
406 .and_then(|s| f.write_str(&s))
407 }
408}
409
410#[cfg(test)]
411mod tests {
412 use crate::{Error, Feature, FeatureCollection, GeoJson, Geometry, Value};
413 use serde_json::json;
414 use std::convert::TryInto;
415 use std::str::FromStr;
416
417 #[test]
418 fn test_geojson_from_reader() {
419 let json_str = r#"{
420 "type": "Feature",
421 "geometry": {
422 "type": "Point",
423 "coordinates": [102.0, 0.5]
424 },
425 "properties": null
426 }"#;
427
428 let g1 = GeoJson::from_reader(json_str.as_bytes()).unwrap();
429
430 let json_value = json!({
431 "type": "Feature",
432 "geometry": {
433 "type": "Point",
434 "coordinates": [102.0, 0.5]
435 },
436 "properties": null,
437 });
438
439 let g2: GeoJson = json_value.try_into().unwrap();
440
441 assert_eq!(g1, g2);
442 }
443
444 #[test]
445 fn test_geojson_from_value() {
446 let json_value = json!({
447 "type": "Feature",
448 "geometry": {
449 "type": "Point",
450 "coordinates": [102.0, 0.5]
451 },
452 "properties": null,
453 });
454
455 assert!(json_value.is_object());
456
457 let geojson: GeoJson = json_value.try_into().unwrap();
458
459 assert_eq!(
460 geojson,
461 GeoJson::Feature(Feature {
462 bbox: None,
463 geometry: Some(Geometry::new(Value::Point(vec![102.0, 0.5]))),
464 id: None,
465 properties: None,
466 foreign_members: None,
467 })
468 );
469 }
470
471 #[test]
472 fn test_geojson_from_features() {
473 let features: Vec<Feature> = vec![
474 Value::Point(vec![0., 0., 0.]).into(),
475 Value::Point(vec![1., 1., 1.]).into(),
476 ];
477
478 let geojson: GeoJson = features.into();
479 assert_eq!(
480 geojson,
481 GeoJson::FeatureCollection(FeatureCollection {
482 features: vec![
483 Feature {
484 bbox: None,
485 geometry: Some(Geometry::new(Value::Point(vec![0., 0., 0.]))),
486 id: None,
487 properties: None,
488 foreign_members: None,
489 },
490 Feature {
491 bbox: None,
492 geometry: Some(Geometry::new(Value::Point(vec![1., 1., 1.]))),
493 id: None,
494 properties: None,
495 foreign_members: None,
496 },
497 ],
498 bbox: None,
499 foreign_members: None,
500 })
501 );
502 }
503
504 #[test]
505 fn test_missing_properties_key() {
506 let json_value = json!({
507 "type": "Feature",
508 "geometry": {
509 "type": "Point",
510 "coordinates": [102.0, 0.5]
511 },
512 });
513
514 assert!(json_value.is_object());
515
516 let geojson: GeoJson = json_value.try_into().unwrap();
517 assert_eq!(
518 geojson,
519 GeoJson::Feature(Feature {
520 bbox: None,
521 geometry: Some(Geometry::new(Value::Point(vec![102.0, 0.5]))),
522 id: None,
523 properties: None,
524 foreign_members: None,
525 })
526 );
527 }
528
529 #[test]
530 fn test_invalid_json() {
531 let geojson_str = r#"{
532 "type": "FeatureCollection",
533 "features": [
534 !INTENTIONAL_TYPO! {
535 "type": "Feature",
536 "properties": {},
537 "geometry": {
538 "type": "Point",
539 "coordinates": [
540 -0.13583511114120483,
541 51.5218870403801
542 ]
543 }
544 }
545 ]
546 }"#;
547 assert!(matches!(
548 GeoJson::from_str(geojson_str),
549 Err(Error::MalformedJson(_))
550 ))
551 }
552}