use serde::de::*; use serde::ser::*; use serde::*; use std::fmt; use std::marker::PhantomData; use crate::types::*; const WGS84_SRID: Option = Some(4326); macro_rules! check_srid_wgs84 { ($x:ident) => { if $x.srid.is_some() && $x.srid != WGS84_SRID { return Err(ser::Error::custom(format!( "Invalid SRID {}", $x.srid.unwrap() ))); } }; } pub trait GeoJsonGeometry { fn to_geo_coordinates(&self) -> Vec; fn from_geo_coordinates(coordinates: Vec) -> Result where Self: Sized; } struct GeometryVisitor { expected_type: String, marker: PhantomData (T, V)>, } impl GeometryVisitor { fn new(expected_type: &str) -> Self { GeometryVisitor { expected_type: expected_type.to_string(), marker: PhantomData, } } } impl<'de, T: GeoJsonGeometry, V: Deserialize<'de>> Visitor<'de> for GeometryVisitor { // The type that our Visitor is going to produce. type Value = T; // Format a message stating what data this Visitor expects to receive. fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_fmt(format_args!("a GeoJson {}", self.expected_type)) } // Deserialize geometry from an abstract "map" provided by the // Deserializer. The MapAccess input is a callback provided by // the Deserializer to let us see each entry in the map. fn visit_map(self, mut access: M) -> Result where M: MapAccess<'de>, V: Deserialize<'de>, { let mut point: Option = None; while let Some(key) = access.next_key::()? { match key.as_str() { "type" => { let t = access.next_value::()?; if t != self.expected_type { return Err(de::Error::custom(format_args!( "unknown type `{}`, expected {}", t, self.expected_type ))); } } "coordinates" => { let v = access.next_value::>()?; match T::from_geo_coordinates(v) { Ok(p) => point = Some(p), Err(err) => { return Err(de::Error::custom(format!("invalid coordinates: {}", err))); } } } _ => { return Err(de::Error::unknown_field(&key, &["type", "coordinates"])); } } } if point.is_none() { return Err(de::Error::missing_field("coordinates")); } Ok(point.unwrap()) } } impl GeoJsonGeometry for Point { fn to_geo_coordinates(&self) -> Vec { vec![self.x, self.y] } fn from_geo_coordinates(coordinates: Vec) -> Result { if coordinates.len() != 2 { return Err(PointConstructorError { reason: format!("invalid size {:?} for Point", coordinates.len()).to_string(), }); } Ok(Point::new(coordinates[0], coordinates[1], WGS84_SRID)) } } impl Serialize for Point { fn serialize(&self, serializer: S) -> Result where S: Serializer, { check_srid_wgs84!(self); let mut state = serializer.serialize_struct("Point", 2)?; state.serialize_field("type", "Point")?; state.serialize_field("coordinates", &self.to_geo_coordinates())?; state.end() } } impl<'de> Deserialize<'de> for Point { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(GeometryVisitor::::new("Point")) } } impl GeoJsonGeometry for PointZ { fn to_geo_coordinates(&self) -> Vec { vec![self.x, self.y, self.z] } fn from_geo_coordinates(coordinates: Vec) -> Result { if coordinates.len() != 3 { return Err(PointConstructorError { reason: format!("invalid size {:?} for PointZ", coordinates.len()).to_string(), }); } Ok(PointZ::new( coordinates[0], coordinates[1], coordinates[2], WGS84_SRID, )) } } impl Serialize for PointZ { fn serialize(&self, serializer: S) -> Result where S: Serializer, { check_srid_wgs84!(self); let mut state = serializer.serialize_struct("Point", 2)?; state.serialize_field("type", "Point")?; state.serialize_field("coordinates", &self.to_geo_coordinates())?; state.end() } } impl<'de> Deserialize<'de> for PointZ { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(GeometryVisitor::::new("Point")) } } impl + PointT> GeoJsonGeometry> for MultiPoint { fn to_geo_coordinates(&self) -> Vec> { self.points .iter() .map(|p| p.to_geo_coordinates()) .collect::>>() } fn from_geo_coordinates(coordinates: Vec>) -> Result { let mut multi_point = MultiPoint:: { points: vec![], srid: WGS84_SRID, }; for p in coordinates { multi_point.points.push(T::from_geo_coordinates(p)?); } Ok(multi_point) } } impl + PointT> Serialize for MultiPoint { fn serialize(&self, serializer: S) -> Result where S: Serializer, { check_srid_wgs84!(self); let coordinates = self.to_geo_coordinates(); let mut state = serializer.serialize_struct("MultiPoint", 2)?; state.serialize_field("type", "MultiPoint")?; state.serialize_field("coordinates", &coordinates)?; state.end() } } impl<'de, T: GeoJsonGeometry + PointT> Deserialize<'de> for MultiPoint { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(GeometryVisitor::, Vec>::new( "MultiPoint", )) } } impl + PointT> GeoJsonGeometry> for LineString { fn to_geo_coordinates(&self) -> Vec> { self.points .iter() .map(|p| p.to_geo_coordinates()) .collect::>>() } fn from_geo_coordinates(coordinates: Vec>) -> Result { let mut multi_point = LineString:: { points: vec![], srid: WGS84_SRID, }; for p in coordinates { multi_point.points.push(T::from_geo_coordinates(p)?); } Ok(multi_point) } } impl + PointT> Serialize for LineString { fn serialize(&self, serializer: S) -> Result where S: Serializer, { check_srid_wgs84!(self); let coordinates = self.to_geo_coordinates(); let mut state = serializer.serialize_struct("LineString", 2)?; state.serialize_field("type", "LineString")?; state.serialize_field("coordinates", &coordinates)?; state.end() } } impl<'de, T: GeoJsonGeometry + PointT> Deserialize<'de> for LineString { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(GeometryVisitor::, Vec>::new( "LineString", )) } } impl + PointT> GeoJsonGeometry>> for MultiLineString { fn to_geo_coordinates(&self) -> Vec>> { self.lines .iter() .map(|line| line.to_geo_coordinates()) .collect::>>>() } fn from_geo_coordinates( coordinates: Vec>>, ) -> Result { let mut multi_line_string = MultiLineString:: { lines: vec![], srid: WGS84_SRID, }; for line in coordinates { multi_line_string .lines .push(LineString::from_geo_coordinates(line)?); } Ok(multi_line_string) } } impl + PointT> Serialize for MultiLineString { fn serialize(&self, serializer: S) -> Result where S: Serializer, { check_srid_wgs84!(self); let coordinates = self.to_geo_coordinates(); let mut state = serializer.serialize_struct("MultiLineString", 2)?; state.serialize_field("type", "MultiLineString")?; state.serialize_field("coordinates", &coordinates)?; state.end() } } impl<'de, T: GeoJsonGeometry + PointT> Deserialize<'de> for MultiLineString { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(GeometryVisitor::, Vec>>::new( "MultiLineString", )) } } impl + PointT + Clone> GeoJsonGeometry>> for Polygon { fn to_geo_coordinates(&self) -> Vec>> { self.rings .iter() .map(|ring| ring.iter().map(|p| p.to_geo_coordinates()).collect()) .collect::>>>() } fn from_geo_coordinates( coordinates: Vec>>, ) -> Result { let mut polygon = Polygon:: { rings: vec![], srid: WGS84_SRID, }; for ring in coordinates { polygon.add_ring(); for p in ring { polygon.add_point(T::from_geo_coordinates(p)?); } } Ok(polygon) } } impl + PointT + Clone> Serialize for Polygon { fn serialize(&self, serializer: S) -> Result where S: Serializer, { check_srid_wgs84!(self); let coordinates = self.to_geo_coordinates(); let mut state = serializer.serialize_struct("Polygon", 2)?; state.serialize_field("type", "Polygon")?; state.serialize_field("coordinates", &coordinates)?; state.end() } } impl<'de, T: GeoJsonGeometry + PointT + Clone> Deserialize<'de> for Polygon { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(GeometryVisitor::, Vec>>::new("Polygon")) } } impl + PointT + Clone> GeoJsonGeometry>>> for MultiPolygon { fn to_geo_coordinates(&self) -> Vec>>> { self.polygons .iter() .map(|polygon| polygon.to_geo_coordinates()) .collect::>>>>() } fn from_geo_coordinates( coordinates: Vec>>>, ) -> Result { let mut multi_polygon = MultiPolygon:: { polygons: vec![], srid: WGS84_SRID, }; for coordinate in coordinates { let polygon = Polygon::::from_geo_coordinates(coordinate)?; multi_polygon.polygons.push(polygon); } Ok(multi_polygon) } } impl + PointT + Clone> Serialize for MultiPolygon { fn serialize(&self, serializer: S) -> Result where S: Serializer, { check_srid_wgs84!(self); let coordinates = self.to_geo_coordinates(); let mut state = serializer.serialize_struct("MultiPolygon", 2)?; state.serialize_field("type", "MultiPolygon")?; state.serialize_field("coordinates", &coordinates)?; state.end() } } impl<'de, T: GeoJsonGeometry + PointT + Clone> Deserialize<'de> for MultiPolygon { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(GeometryVisitor::, Vec>>>::new( "MultiPolygon", )) } } impl + PointT + Clone + Serialize> Serialize for GeometryContainer { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match self { GeometryContainer::Point(g) => g.serialize(serializer), GeometryContainer::MultiPoint(g) => g.serialize(serializer), GeometryContainer::LineString(g) => g.serialize(serializer), GeometryContainer::MultiLineString(g) => g.serialize(serializer), GeometryContainer::Polygon(g) => g.serialize(serializer), GeometryContainer::MultiPolygon(g) => g.serialize(serializer), GeometryContainer::GeometryCollection(g) => g.serialize(serializer), } } } impl + PointT + Clone + Serialize> Serialize for GeometryCollection { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("GeometryCollection", 2)?; state.serialize_field("type", "GeometryCollection")?; state.serialize_field("geometries", &self.geometries)?; state.end() } } struct GeometryCollectionVisitor { marker: PhantomData T>, } impl GeometryCollectionVisitor { fn new() -> Self { GeometryCollectionVisitor { marker: PhantomData, } } } impl<'de, T: GeoJsonGeometry + PointT + Clone + Deserialize<'de>> Visitor<'de> for GeometryCollectionVisitor { // The type that our Visitor is going to produce. type Value = GeometryCollection; // Format a message stating what data this Visitor expects to receive. fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_fmt(format_args!("a GeoJson GeometryCollection")) } // Deserialize GeometryCollection from an abstract "map" provided by the // Deserializer. The MapAccess input is a callback provided by // the Deserializer to let us see each entry in the map. fn visit_map(self, mut access: M) -> Result where M: MapAccess<'de>, { let mut geometries: Option>> = None; while let Some(key) = access.next_key::()? { match key.as_str() { "type" => { let t = access.next_value::()?; if t != "GeometryCollection" { return Err(de::Error::custom(format_args!( "unknown type `{}`, expected GeometryCollection", t ))); } } "geometries" => { let v = access.next_value::>>()?; geometries = Some(v); } _ => { return Err(de::Error::unknown_field(&key, &["type", "coordinates"])); } } } if geometries.is_none() { return Err(de::Error::missing_field("geometries")); } Ok(GeometryCollection:: { geometries: geometries.unwrap(), srid: WGS84_SRID, }) } } impl<'de, T: GeoJsonGeometry + PointT + Clone + Deserialize<'de>> Deserialize<'de> for GeometryCollection { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(GeometryCollectionVisitor::::new()) } } impl + PointT + Clone + Serialize, P: Serialize> Serialize for Feature { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("Feature", 2)?; state.serialize_field("type", "Feature")?; if let Some(id) = &self.id { state.serialize_field("id", &id)?; } state.serialize_field("geometry", &self.geometry)?; state.serialize_field("properties", &self.properties)?; state.end() } } impl + PointT + Clone + Serialize, P: Serialize> Serialize for FeatureCollection { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut state = serializer.serialize_struct("FeatureCollection", 2)?; state.serialize_field("type", "FeatureCollection")?; state.serialize_field("features", &self.features)?; state.end() } } #[cfg(test)] mod tests { // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; #[derive(Debug, PartialEq, Serialize, Deserialize)] struct TestFeatureProperties { pub name: String, pub size: i32, } #[test] fn test_point_serde() { let point = Point::new(72.0, 64.0, WGS84_SRID); let expected_json = "{\"type\":\"Point\",\"coordinates\":[72.0,64.0]}"; let point_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(point, point_from_json); let point_json = serde_json::to_string(&point).unwrap(); assert_eq!(expected_json, point_json); } #[test] fn test_pointz_serde() { let point = PointZ::new(72.0, 64.0, 52.0, WGS84_SRID); let expected_json = "{\"type\":\"Point\",\"coordinates\":[72.0,64.0,52.0]}"; let point_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(point, point_from_json); let point_json = serde_json::to_string(&point).unwrap(); assert_eq!(expected_json, point_json); } #[test] fn test_multi_point_serde() { let mut multi_point = MultiPoint:: { points: vec![], srid: WGS84_SRID, }; multi_point.add_point(Point::new(1.0, 2.0, WGS84_SRID)); multi_point.add_point(Point::new(3.0, 4.0, WGS84_SRID)); multi_point.add_point(Point::new(5.0, 6.0, WGS84_SRID)); let expected_json = "{\"type\":\"MultiPoint\",\"coordinates\":[[1.0,2.0],[3.0,4.0],[5.0,6.0]]}"; let multi_point_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(multi_point, multi_point_from_json); let multi_point_json = serde_json::to_string(&multi_point).unwrap(); assert_eq!(expected_json, multi_point_json); } #[test] fn test_line_string_serde() { let mut line_string = LineString:: { points: vec![], srid: WGS84_SRID, }; line_string.add_point(Point::new(1.0, 2.0, WGS84_SRID)); line_string.add_point(Point::new(3.0, 4.0, WGS84_SRID)); line_string.add_point(Point::new(5.0, 6.0, WGS84_SRID)); let expected_json = "{\"type\":\"LineString\",\"coordinates\":[[1.0,2.0],[3.0,4.0],[5.0,6.0]]}"; let line_string_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(line_string, line_string_from_json); let line_string_json = serde_json::to_string(&line_string).unwrap(); assert_eq!(expected_json, line_string_json); } #[test] fn test_multi_line_string_serde() { let mut multi_line_string = MultiLineString:: { lines: vec![], srid: WGS84_SRID, }; multi_line_string.add_point(Point::new(1.0, 2.0, WGS84_SRID)); multi_line_string.add_point(Point::new(3.0, 4.0, WGS84_SRID)); multi_line_string.add_point(Point::new(5.0, 6.0, WGS84_SRID)); let expected_json = "{\"type\":\"MultiLineString\",\"coordinates\":[[[1.0,2.0],[3.0,4.0],[5.0,6.0]]]}"; let multi_line_string_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(multi_line_string, multi_line_string_from_json); let multi_line_string_json = serde_json::to_string(&multi_line_string).unwrap(); assert_eq!(expected_json, multi_line_string_json); } #[test] fn test_polygon_serde() { let mut polygon = Polygon:: { rings: vec![], srid: WGS84_SRID, }; polygon.add_point(Point::new(1.0, 2.0, WGS84_SRID)); polygon.add_point(Point::new(3.0, 4.0, WGS84_SRID)); polygon.add_point(Point::new(5.0, 6.0, WGS84_SRID)); polygon.add_point(Point::new(1.0, 2.0, WGS84_SRID)); let expected_json = "{\"type\":\"Polygon\",\"coordinates\":[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]]}"; let polygon_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(polygon, polygon_from_json); let polygon_json = serde_json::to_string(&polygon).unwrap(); assert_eq!(expected_json, polygon_json); } #[test] fn test_multi_polygon_serde() { let mut polygon = Polygon:: { rings: vec![], srid: WGS84_SRID, }; polygon.add_point(PointZ::new(1.0, 2.0, 3.0, WGS84_SRID)); polygon.add_point(PointZ::new(4.0, 5.0, 6.0, WGS84_SRID)); polygon.add_point(PointZ::new(7.0, 8.0, 9.0, WGS84_SRID)); polygon.add_point(PointZ::new(1.0, 2.0, 3.0, WGS84_SRID)); let multi_polygon = MultiPolygon:: { polygons: vec![polygon], srid: WGS84_SRID, }; let expected_json = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1.0,2.0,3.0],[4.0,5.0,6.0],[7.0,8.0,9.0],[1.0,2.0,3.0]]]]}"; let multi_polygon_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(multi_polygon, multi_polygon_from_json); let multi_polygon_json = serde_json::to_string(&multi_polygon).unwrap(); assert_eq!(expected_json, multi_polygon_json); } #[test] fn test_geometry_collection_serde() { let point = Point::new(1.0, 2.0, WGS84_SRID); let mut line_string = LineString:: { points: vec![], srid: WGS84_SRID, }; line_string.add_point(Point::new(3.0, 4.0, WGS84_SRID)); line_string.add_point(Point::new(5.0, 6.0, WGS84_SRID)); let geometry_collection = GeometryCollection:: { geometries: vec![ GeometryContainer::Point(point), GeometryContainer::LineString(line_string), ], srid: WGS84_SRID, }; let expected_json = "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1.0,2.0]},{\"type\":\"LineString\",\"coordinates\":[[3.0,4.0],[5.0,6.0]]}]}"; let geometry_collection_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(geometry_collection, geometry_collection_from_json); let geometry_collection_json = serde_json::to_string(&geometry_collection).unwrap(); assert_eq!(expected_json, geometry_collection_json); } #[test] fn test_feature_collection_serde() { let point = Point::new(1.0, 2.0, WGS84_SRID); let feature1 = Feature:: { id: None, geometry: Some(GeometryContainer::Point(point)), properties: Some(TestFeatureProperties { name: "Test".to_string(), size: 123, }), }; let feature2 = Feature:: { id: Some("Test".to_string()), geometry: None, properties: None, }; let feature_collection = FeatureCollection:: { features: vec![feature1, feature2], }; let expected_json = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[1.0,2.0]},\"properties\":{\"name\":\"Test\",\"size\":123}},{\"type\":\"Feature\",\"id\":\"Test\",\"geometry\":null,\"properties\":null}]}"; let feature_collection_from_json = serde_json::from_str(expected_json).unwrap(); assert_eq!(feature_collection, feature_collection_from_json); let feature_collection_json = serde_json::to_string(&feature_collection).unwrap(); assert_eq!(expected_json, feature_collection_json); } #[test] fn test_non_wgs84_serde() { let point = Point::new(72.0, 64.0, Some(4324)); let point_json = serde_json::to_string(&point); assert_eq!(true, point_json.is_err()); } #[test] fn test_no_srid_serde() { let point = Point::new(72.0, 64.0, None); let point_json = serde_json::to_string(&point); assert_eq!(true, point_json.is_ok()); } }