use serde::{Serialize, Deserialize}; use std::fmt; macro_rules! tagtype { ($name:ident: $tag:literal) => { #[derive(Clone, Copy, Default, Debug)] pub struct $name; impl Serialize for $name { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_str($tag) } } impl<'de> Deserialize<'de> for $name { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { struct Visitor; impl serde::de::Visitor<'_> for Visitor { type Value = $name; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "tag type {:?}", $tag) } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { if v != $tag { return Err(E::invalid_value(serde::de::Unexpected::Str(v), &$tag)); } Ok($name) } } deserializer.deserialize_str(Visitor) } } }; } tagtype!(TagFeatureCollection: "FeatureCollection"); #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FeatureCollection { pub r#type: TagFeatureCollection, pub features: Vec, } tagtype!(TagFeature: "Feature"); #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Feature { pub r#type: TagFeature, pub id: String, pub properties: FeatureProperties, pub geometry: Geometry, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FeatureProperties { pub name: String, } #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(tag = "type")] pub enum Geometry { Polygon { coordinates: PolygonData, }, MultiPolygon { coordinates: Vec, }, } // first list of points is outer "hull" (should be clockwise), remaining list of points are holes (counterclockwise) #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PolygonData(pub Vec>); #[derive(Clone, Copy, Debug)] pub struct Position { pub longitude: f32, pub latitude: f32, } impl Serialize for Position { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { (self.longitude, self.latitude).serialize(serializer) } } impl<'de> Deserialize<'de> for Position { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { <(f32, f32)>::deserialize(deserializer).map(|(longitude, latitude)| Position { longitude, latitude }) } }