use serde::{Deserialize, Serialize};
use crate::Bbox;
pub type Position = Vec<f64>;
macro_rules! coord_geometry {
($name:ident, $tag:ident, $lit:literal, $coords:ty, $ts_coords:ty) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
pub enum $tag {
#[serde(rename = $lit)]
$name,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
pub struct $name {
// `specta` reads `#[serde(rename)]`, so the wire/TS name is `type`.
#[serde(rename = "type")]
pub r#type: $tag,
#[cfg_attr(feature = "specta", specta(type = $ts_coords))]
pub coordinates: $coords,
#[cfg_attr(feature = "specta", specta(type = Bbox, optional))]
pub bbox: Option<Bbox>,
}
impl $name {
pub fn new(coordinates: $coords) -> Self {
Self {
r#type: $tag::$name,
coordinates,
bbox: None,
}
}
}
impl Serialize for $name {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(2 + self.bbox.is_some() as usize))?;
map.serialize_entry("type", $lit)?;
map.serialize_entry("coordinates", &self.coordinates)?;
if let Some(bbox) = &self.bbox {
map.serialize_entry("bbox", bbox)?;
}
map.end()
}
}
};
}
coord_geometry!(Point, PointType, "Point", Position, Vec<crate::TsNumber>);
coord_geometry!(
MultiPoint,
MultiPointType,
"MultiPoint",
Vec<Position>,
Vec<Vec<crate::TsNumber>>
);
coord_geometry!(
LineString,
LineStringType,
"LineString",
Vec<Position>,
Vec<Vec<crate::TsNumber>>
);
coord_geometry!(
MultiLineString,
MultiLineStringType,
"MultiLineString",
Vec<Vec<Position>>,
Vec<Vec<Vec<crate::TsNumber>>>
);
coord_geometry!(
Polygon,
PolygonType,
"Polygon",
Vec<Vec<Position>>,
Vec<Vec<Vec<crate::TsNumber>>>
);
coord_geometry!(
MultiPolygon,
MultiPolygonType,
"MultiPolygon",
Vec<Vec<Vec<Position>>>,
Vec<Vec<Vec<Vec<crate::TsNumber>>>>
);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
pub enum GeometryCollectionType {
GeometryCollection,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
pub struct GeometryCollection {
#[serde(rename = "type")]
pub r#type: GeometryCollectionType,
pub geometries: Vec<Geometry>,
#[cfg_attr(feature = "specta", specta(type = Bbox, optional))]
pub bbox: Option<Bbox>,
}
impl GeometryCollection {
pub fn new(geometries: Vec<Geometry>) -> Self {
Self {
r#type: GeometryCollectionType::GeometryCollection,
geometries,
bbox: None,
}
}
}
impl Serialize for GeometryCollection {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(2 + self.bbox.is_some() as usize))?;
map.serialize_entry("type", "GeometryCollection")?;
map.serialize_entry("geometries", &self.geometries)?;
if let Some(bbox) = &self.bbox {
map.serialize_entry("bbox", bbox)?;
}
map.end()
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
#[serde(untagged)]
pub enum Geometry {
Point(Point),
MultiPoint(MultiPoint),
LineString(LineString),
MultiLineString(MultiLineString),
Polygon(Polygon),
MultiPolygon(MultiPolygon),
GeometryCollection(GeometryCollection),
}
impl TryFrom<Geometry> for geojson::Geometry {
type Error = serde_json::Error;
fn try_from(g: Geometry) -> Result<Self, Self::Error> {
serde_json::from_value(serde_json::to_value(g)?)
}
}
impl TryFrom<geojson::Geometry> for Geometry {
type Error = serde_json::Error;
fn try_from(g: geojson::Geometry) -> Result<Self, Self::Error> {
serde_json::from_value(serde_json::to_value(g)?)
}
}