1use std::str::FromStr;
16use std::{convert::TryFrom, fmt};
17
18use crate::errors::{Error, Result};
19use crate::{util, Bbox, LineStringType, PointType, PolygonType};
20use crate::{JsonObject, JsonValue};
21use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
22
23#[derive(Clone, Debug, PartialEq)]
49pub enum Value {
50 Point(PointType),
54
55 MultiPoint(Vec<PointType>),
59
60 LineString(LineStringType),
64
65 MultiLineString(Vec<LineStringType>),
69
70 Polygon(PolygonType),
74
75 MultiPolygon(Vec<PolygonType>),
79
80 GeometryCollection(Vec<Geometry>),
84}
85
86impl Value {
87 pub fn type_name(&self) -> &'static str {
88 match self {
89 Value::Point(..) => "Point",
90 Value::MultiPoint(..) => "MultiPoint",
91 Value::LineString(..) => "LineString",
92 Value::MultiLineString(..) => "MultiLineString",
93 Value::Polygon(..) => "Polygon",
94 Value::MultiPolygon(..) => "MultiPolygon",
95 Value::GeometryCollection(..) => "GeometryCollection",
96 }
97 }
98}
99
100impl<'a> From<&'a Value> for JsonObject {
101 fn from(value: &'a Value) -> JsonObject {
102 let mut map = JsonObject::new();
103 map.insert(
104 String::from("type"),
105 ::serde_json::to_value(value.type_name()).unwrap(),
107 );
108 map.insert(
109 String::from(match value {
110 Value::GeometryCollection(..) => "geometries",
111 _ => "coordinates",
112 }),
113 ::serde_json::to_value(value).unwrap(),
115 );
116 map
117 }
118}
119
120impl Value {
121 pub fn from_json_object(object: JsonObject) -> Result<Self> {
122 Self::try_from(object)
123 }
124
125 pub fn from_json_value(value: JsonValue) -> Result<Self> {
126 Self::try_from(value)
127 }
128
129 fn serialize_to_map<SM: SerializeMap>(
130 &self,
131 map: &mut SM,
132 ) -> std::result::Result<(), SM::Error> {
133 map.serialize_entry("type", self.type_name())?;
134 map.serialize_entry(
135 match self {
136 Value::GeometryCollection(..) => "geometries",
137 _ => "coordinates",
138 },
139 self,
140 )?;
141 Ok(())
142 }
143}
144
145impl TryFrom<JsonObject> for Value {
146 type Error = Error;
147
148 fn try_from(mut object: JsonObject) -> Result<Self> {
149 util::get_value(&mut object)
150 }
151}
152
153impl TryFrom<JsonValue> for Value {
154 type Error = Error;
155
156 fn try_from(value: JsonValue) -> Result<Self> {
157 if let JsonValue::Object(obj) = value {
158 Self::try_from(obj)
159 } else {
160 Err(Error::GeoJsonExpectedObject(value))
161 }
162 }
163}
164
165impl fmt::Display for Value {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 ::serde_json::to_string(&JsonObject::from(self))
168 .map_err(|_| fmt::Error)
169 .and_then(|s| f.write_str(&s))
170 }
171}
172
173impl<'a> From<&'a Value> for JsonValue {
174 fn from(value: &'a Value) -> JsonValue {
175 ::serde_json::to_value(value).unwrap()
176 }
177}
178
179impl Serialize for Value {
180 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
181 where
182 S: Serializer,
183 {
184 match self {
185 Value::Point(x) => x.serialize(serializer),
186 Value::MultiPoint(x) => x.serialize(serializer),
187 Value::LineString(x) => x.serialize(serializer),
188 Value::MultiLineString(x) => x.serialize(serializer),
189 Value::Polygon(x) => x.serialize(serializer),
190 Value::MultiPolygon(x) => x.serialize(serializer),
191 Value::GeometryCollection(x) => x.serialize(serializer),
192 }
193 }
194}
195
196#[derive(Clone, Debug, PartialEq)]
262pub struct Geometry {
263 pub bbox: Option<Bbox>,
267 pub value: Value,
268 pub foreign_members: Option<JsonObject>,
272}
273
274impl Geometry {
275 pub fn new(value: Value) -> Self {
278 Geometry {
279 bbox: None,
280 value,
281 foreign_members: None,
282 }
283 }
284}
285
286impl<'a> From<&'a Geometry> for JsonObject {
287 fn from(geometry: &'a Geometry) -> JsonObject {
288 let mut map = JsonObject::from(&geometry.value);
289 if let Some(ref bbox) = geometry.bbox {
290 map.insert(String::from("bbox"), ::serde_json::to_value(bbox).unwrap());
291 }
292
293 if let Some(ref foreign_members) = geometry.foreign_members {
294 for (key, value) in foreign_members {
295 map.insert(key.to_owned(), value.to_owned());
296 }
297 }
298 map
299 }
300}
301
302impl Geometry {
303 pub fn from_json_object(object: JsonObject) -> Result<Self> {
304 Self::try_from(object)
305 }
306
307 pub fn from_json_value(value: JsonValue) -> Result<Self> {
308 Self::try_from(value)
309 }
310
311 fn serialize_to_map<SM: SerializeMap>(
312 &self,
313 map: &mut SM,
314 ) -> std::result::Result<(), SM::Error> {
315 self.value.serialize_to_map(map)?;
316 if let Some(ref bbox) = self.bbox {
317 map.serialize_entry("bbox", bbox)?;
318 }
319
320 if let Some(ref foreign_members) = self.foreign_members {
321 for (key, value) in foreign_members {
322 map.serialize_entry(key, value)?
323 }
324 }
325 Ok(())
326 }
327}
328
329impl TryFrom<JsonObject> for Geometry {
330 type Error = Error;
331
332 fn try_from(mut object: JsonObject) -> Result<Self> {
333 let bbox = util::get_bbox(&mut object)?;
334 let value = util::get_value(&mut object)?;
335 let foreign_members = util::get_foreign_members(object)?;
336 Ok(Geometry {
337 bbox,
338 value,
339 foreign_members,
340 })
341 }
342}
343
344impl TryFrom<JsonValue> for Geometry {
345 type Error = Error;
346
347 fn try_from(value: JsonValue) -> Result<Self> {
348 if let JsonValue::Object(obj) = value {
349 Self::try_from(obj)
350 } else {
351 Err(Error::GeoJsonExpectedObject(value))
352 }
353 }
354}
355
356impl FromStr for Geometry {
357 type Err = Error;
358
359 fn from_str(s: &str) -> Result<Self> {
360 Self::try_from(crate::GeoJson::from_str(s)?)
361 }
362}
363
364impl Serialize for Geometry {
365 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
366 where
367 S: Serializer,
368 {
369 let mut map = serializer.serialize_map(None)?;
370 self.serialize_to_map(&mut map)?;
371 map.end()
372 }
373}
374
375impl<'de> Deserialize<'de> for Geometry {
376 fn deserialize<D>(deserializer: D) -> std::result::Result<Geometry, D::Error>
377 where
378 D: Deserializer<'de>,
379 {
380 use serde::de::Error as SerdeError;
381
382 let val = JsonObject::deserialize(deserializer)?;
383
384 Geometry::from_json_object(val).map_err(|e| D::Error::custom(e.to_string()))
385 }
386}
387
388impl<V> From<V> for Geometry
389where
390 V: Into<Value>,
391{
392 fn from(v: V) -> Geometry {
393 Geometry::new(v.into())
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use crate::{Error, GeoJson, Geometry, JsonObject, Value};
400 use serde_json::json;
401 use std::str::FromStr;
402
403 fn encode(geometry: &Geometry) -> String {
404 serde_json::to_string(&geometry).unwrap()
405 }
406 fn decode(json_string: String) -> GeoJson {
407 json_string.parse().unwrap()
408 }
409
410 #[test]
411 fn encode_decode_geometry() {
412 let geometry_json_str = "{\"type\":\"Point\",\"coordinates\":[1.1,2.1]}";
413 let geometry = Geometry {
414 value: Value::Point(vec![1.1, 2.1]),
415 bbox: None,
416 foreign_members: None,
417 };
418
419 let json_string = encode(&geometry);
421 assert_eq!(json_string, geometry_json_str);
422
423 let decoded_geometry = match decode(json_string) {
425 GeoJson::Geometry(g) => g,
426 _ => unreachable!(),
427 };
428 assert_eq!(decoded_geometry, geometry);
429 }
430
431 #[test]
432 fn test_geometry_from_value() {
433 use serde_json::json;
434 use std::convert::TryInto;
435
436 let json_value = json!({
437 "type": "Point",
438 "coordinates": [
439 0.0, 0.1
440 ],
441 });
442 assert!(json_value.is_object());
443
444 let geometry: Geometry = json_value.try_into().unwrap();
445 assert_eq!(
446 geometry,
447 Geometry {
448 value: Value::Point(vec![0.0, 0.1]),
449 bbox: None,
450 foreign_members: None,
451 }
452 )
453 }
454
455 #[test]
456 fn test_geometry_display() {
457 let v = Value::LineString(vec![vec![0.0, 0.1], vec![0.1, 0.2], vec![0.2, 0.3]]);
458 let geometry = Geometry::new(v);
459 assert_eq!(
460 geometry.to_string(),
461 "{\"type\":\"LineString\",\"coordinates\":[[0.0,0.1],[0.1,0.2],[0.2,0.3]]}"
462 );
463 }
464
465 #[test]
466 fn test_value_display() {
467 let v = Value::LineString(vec![vec![0.0, 0.1], vec![0.1, 0.2], vec![0.2, 0.3]]);
468 assert_eq!(
469 "{\"coordinates\":[[0.0,0.1],[0.1,0.2],[0.2,0.3]],\"type\":\"LineString\"}",
470 v.to_string()
471 );
472 }
473
474 #[test]
475 fn encode_decode_geometry_with_foreign_member() {
476 let geometry_json_str =
477 "{\"type\":\"Point\",\"coordinates\":[1.1,2.1],\"other_member\":true}";
478 let mut foreign_members = JsonObject::new();
479 foreign_members.insert(
480 String::from("other_member"),
481 serde_json::to_value(true).unwrap(),
482 );
483 let geometry = Geometry {
484 value: Value::Point(vec![1.1, 2.1]),
485 bbox: None,
486 foreign_members: Some(foreign_members),
487 };
488
489 let json_string = encode(&geometry);
491 assert_eq!(json_string, geometry_json_str);
492
493 let decoded_geometry = match decode(geometry_json_str.into()) {
495 GeoJson::Geometry(g) => g,
496 _ => unreachable!(),
497 };
498 assert_eq!(decoded_geometry, geometry);
499 }
500
501 #[test]
502 fn encode_decode_geometry_collection() {
503 let geometry_collection = Geometry {
504 bbox: None,
505 value: Value::GeometryCollection(vec![
506 Geometry {
507 bbox: None,
508 value: Value::Point(vec![100.0, 0.0]),
509 foreign_members: None,
510 },
511 Geometry {
512 bbox: None,
513 value: Value::LineString(vec![vec![101.0, 0.0], vec![102.0, 1.0]]),
514 foreign_members: None,
515 },
516 ]),
517 foreign_members: None,
518 };
519
520 let geometry_collection_string = "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[100.0,0.0]},{\"type\":\"LineString\",\"coordinates\":[[101.0,0.0],[102.0,1.0]]}]}";
521 let json_string = encode(&geometry_collection);
523 assert_eq!(json_string, geometry_collection_string);
524
525 let decoded_geometry = match decode(geometry_collection_string.into()) {
527 GeoJson::Geometry(g) => g,
528 _ => unreachable!(),
529 };
530 assert_eq!(decoded_geometry, geometry_collection);
531 }
532
533 #[test]
534 fn test_from_str_ok() {
535 let geometry_json = json!({
536 "type": "Point",
537 "coordinates": [125.6f64, 10.1]
538 })
539 .to_string();
540
541 let geometry = Geometry::from_str(&geometry_json).unwrap();
542 assert!(matches!(geometry.value, Value::Point(_)));
543 }
544
545 #[test]
546 fn test_from_str_with_unexpected_type() {
547 let feature_json = json!({
548 "type": "Feature",
549 "geometry": {
550 "type": "Point",
551 "coordinates": [125.6, 10.1]
552 },
553 "properties": {
554 "name": "Dinagat Islands"
555 }
556 })
557 .to_string();
558
559 let actual_failure = Geometry::from_str(&feature_json).unwrap_err();
560 match actual_failure {
561 Error::ExpectedType { actual, expected } => {
562 assert_eq!(actual, "Feature");
563 assert_eq!(expected, "Geometry");
564 }
565 e => panic!("unexpected error: {}", e),
566 };
567 }
568
569 #[test]
570 fn test_reject_too_few_coordinates() {
571 let err = Geometry::from_str(r#"{"type": "Point", "coordinates": []}"#).unwrap_err();
572 assert_eq!(
573 err.to_string(),
574 "A position must contain two or more elements, but got `0`"
575 );
576
577 let err = Geometry::from_str(r#"{"type": "Point", "coordinates": [23.42]}"#).unwrap_err();
578 assert_eq!(
579 err.to_string(),
580 "A position must contain two or more elements, but got `1`"
581 );
582 }
583}