poem_openapi/types/external/
geo.rs1use geo_types::*;
2
3use crate::types::Type;
4
5trait GeoJson {
6 type Coordinates: Type;
7}
8
9macro_rules! impl_geojson_types {
10 ($geometry:tt, $name:literal, $coordinates:ty) => {
11 impl<T: CoordNum + crate::types::Type> GeoJson for $geometry<T> {
12 type Coordinates = $coordinates;
13 }
14
15 impl crate::types::Type for $geometry {
16 const IS_REQUIRED: bool = true;
17 type RawValueType = Self;
18 type RawElementValueType = Self;
19
20 fn name() -> ::std::borrow::Cow<'static, str> {
21 concat!("GeoJSON_", $name).into()
22 }
23
24 fn schema_ref() -> crate::registry::MetaSchemaRef {
25 crate::registry::MetaSchemaRef::Reference(Self::name().into_owned())
26 }
27
28 fn register(registry: &mut crate::registry::Registry) {
29 registry.create_schema::<Self, _>(Self::name().into_owned(), |registry| {
30 String::register(registry);
31 <<Self as GeoJson>::Coordinates>::register(registry);
32 crate::registry::MetaSchema {
33 required: vec!["type", "coordinates"],
34 properties: vec![
35 ("type", String::schema_ref()),
36 (
37 "coordinates",
38 <<Self as GeoJson>::Coordinates>::schema_ref(),
39 ),
40 ],
41 ..crate::registry::MetaSchema::new("object")
42 }
43 })
44 }
45
46 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
47 Some(self)
48 }
49
50 fn raw_element_iter<'a>(
51 &'a self,
52 ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
53 Box::new(IntoIterator::into_iter(self.as_raw_value()))
54 }
55 }
56
57 impl crate::types::ParseFromJSON for $geometry {
58 fn parse_from_json(
59 value: Option<::serde_json::Value>,
60 ) -> Result<Self, crate::types::ParseError<Self>> {
61 let value = value.ok_or(crate::types::ParseError::expected_input())?;
62 Self::try_from(geojson::Geometry::try_from(value)?).map_err(Into::into)
63 }
64 }
65
66 impl crate::types::ToJSON for $geometry {
67 fn to_json(&self) -> Option<::serde_json::Value> {
68 Some(
69 ::serde_json::Map::<String, ::serde_json::Value>::from(
70 &geojson::Geometry::from(self),
71 )
72 .into(),
73 )
74 }
75 }
76 };
77}
78
79impl_geojson_types!(Point, "Point", [T; 2]);
80impl_geojson_types!(MultiPoint, "MultiPoint", Vec<[T; 2]>);
81impl_geojson_types!(LineString, "LineString", Vec<[T; 2]>);
82impl_geojson_types!(MultiLineString, "MultiLineString", Vec<Vec<[T; 2]>>);
83impl_geojson_types!(Polygon, "Polygon", Vec<Vec<[T; 2]>>);
84impl_geojson_types!(MultiPolygon, "MultiPolygon", Vec<Vec<Vec<[T; 2]>>>);
85
86#[cfg(test)]
87mod tests {
88 use geo_types::Point;
89
90 use crate::types::{ParseFromJSON, ToJSON};
91
92 fn point_geo() -> Point {
93 Point::new(1.0, 2.0)
94 }
95
96 fn point_json() -> serde_json::Value {
97 serde_json::json!({
98 "type": "Point",
99 "coordinates": [1.0, 2.0]
100 })
101 }
102
103 #[test]
104 fn serializes_geo_to_json() {
105 assert_eq!(point_json(), point_geo().to_json().unwrap())
106 }
107
108 #[test]
109 fn deserializes_json_to_geo() {
110 assert_eq!(
111 Point::parse_from_json(Some(point_json())).unwrap(),
112 point_geo()
113 )
114 }
115}