use std::fmt;
use std::marker::PhantomData;
use serde::de::{self, Deserializer, MapAccess, Visitor};
use serde::ser::{SerializeMap, Serializer};
use serde::{Deserialize, Serialize};
mod geometry;
pub use geometry::*;
#[cfg(feature = "geo-types")]
mod geo_types_bridge;
#[cfg(feature = "specta")]
pub(crate) struct TsNumber;
#[cfg(feature = "specta")]
impl specta::Type for TsNumber {
fn definition(_: &mut specta::Types) -> specta::datatype::DataType {
specta::datatype::DataType::Primitive(specta::datatype::Primitive::i32)
}
}
pub type Properties = Option<serde_json::Map<String, serde_json::Value>>;
pub type ForeignMembers = serde_json::Map<String, serde_json::Value>;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
#[serde(untagged)]
pub enum Bbox {
D2(
#[cfg_attr(feature = "specta", specta(type = (TsNumber, TsNumber, TsNumber, TsNumber)))]
[f64; 4],
),
D3(
#[cfg_attr(feature = "specta", specta(type = (TsNumber, TsNumber, TsNumber, TsNumber, TsNumber, TsNumber)))]
[f64; 6],
),
}
impl From<Bbox> for Vec<f64> {
fn from(bbox: Bbox) -> Self {
match bbox {
Bbox::D2(a) => a.to_vec(),
Bbox::D3(a) => a.to_vec(),
}
}
}
pub(crate) fn bbox_from_vec(v: Vec<f64>) -> Result<Bbox, serde_json::Error> {
match v.len() {
4 => Ok(Bbox::D2([v[0], v[1], v[2], v[3]])),
6 => Ok(Bbox::D3([v[0], v[1], v[2], v[3], v[4], v[5]])),
n => Err(<serde_json::Error as de::Error>::custom(format!(
"bbox must have 4 or 6 numbers, found {n}"
))),
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
#[serde(untagged)]
pub enum Id {
String(String),
Number(#[cfg_attr(feature = "specta", specta(type = TsNumber))] serde_json::Number),
}
#[derive(Clone, Debug, PartialEq)]
pub struct Feature<G = Geometry, P = Properties> {
pub geometry: G,
pub properties: P,
pub id: Option<Id>,
pub bbox: Option<Bbox>,
pub foreign_members: ForeignMembers,
}
impl<G, P> Feature<G, P> {
pub fn new(geometry: G, properties: P) -> Self {
Self {
geometry,
properties,
id: None,
bbox: None,
foreign_members: ForeignMembers::new(),
}
}
}
impl<G: Serialize, P: Serialize> Serialize for Feature<G, P> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut len = 3; if self.id.is_some() {
len += 1;
}
if self.bbox.is_some() {
len += 1;
}
len += self.foreign_members.len();
let mut map = serializer.serialize_map(Some(len))?;
map.serialize_entry("type", "Feature")?;
map.serialize_entry("geometry", &self.geometry)?;
map.serialize_entry("properties", &self.properties)?;
if let Some(id) = &self.id {
map.serialize_entry("id", id)?;
}
if let Some(bbox) = &self.bbox {
map.serialize_entry("bbox", bbox)?;
}
for (name, value) in &self.foreign_members {
map.serialize_entry(name, value)?;
}
map.end()
}
}
enum FeatureKey {
Type,
Geometry,
Properties,
Id,
Bbox,
Foreign(String),
}
impl<'de> Deserialize<'de> for FeatureKey {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct KeyVisitor;
impl<'de> Visitor<'de> for KeyVisitor {
type Value = FeatureKey;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a GeoJSON Feature member name")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<FeatureKey, E> {
Ok(match v {
"type" => FeatureKey::Type,
"geometry" => FeatureKey::Geometry,
"properties" => FeatureKey::Properties,
"id" => FeatureKey::Id,
"bbox" => FeatureKey::Bbox,
_ => FeatureKey::Foreign(v.to_owned()),
})
}
}
deserializer.deserialize_str(KeyVisitor)
}
}
impl<'de, G: Deserialize<'de>, P: Deserialize<'de>> Deserialize<'de> for Feature<G, P> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct FeatureVisitor<G, P>(PhantomData<(G, P)>);
impl<'de, G: Deserialize<'de>, P: Deserialize<'de>> Visitor<'de> for FeatureVisitor<G, P> {
type Value = Feature<G, P>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a GeoJSON Feature object")
}
fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<Feature<G, P>, M::Error> {
let mut had_type = false;
let mut geometry: Option<G> = None;
let mut properties: Option<P> = None;
let mut id: Option<Id> = None;
let mut bbox: Option<Bbox> = None;
let mut foreign_members = ForeignMembers::new();
while let Some(key) = map.next_key()? {
match key {
FeatureKey::Type => {
let ty: String = map.next_value()?;
if ty != "Feature" {
return Err(de::Error::custom(format!(
"expected `type` to be \"Feature\", found {ty:?}"
)));
}
had_type = true;
}
FeatureKey::Geometry => geometry = Some(map.next_value()?),
FeatureKey::Properties => properties = Some(map.next_value()?),
FeatureKey::Id => id = map.next_value()?,
FeatureKey::Bbox => bbox = map.next_value()?,
FeatureKey::Foreign(name) => {
foreign_members.insert(name, map.next_value()?);
}
}
}
if !had_type {
return Err(de::Error::missing_field("type"));
}
Ok(Feature {
geometry: geometry.ok_or_else(|| de::Error::missing_field("geometry"))?,
properties: properties.ok_or_else(|| de::Error::missing_field("properties"))?,
id,
bbox,
foreign_members,
})
}
}
deserializer.deserialize_map(FeatureVisitor(PhantomData))
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct FeatureCollection<G = Geometry, P = Properties> {
pub features: Vec<Feature<G, P>>,
pub bbox: Option<Bbox>,
pub foreign_members: ForeignMembers,
}
impl<G, P> FromIterator<Feature<G, P>> for FeatureCollection<G, P> {
fn from_iter<I: IntoIterator<Item = Feature<G, P>>>(iter: I) -> Self {
Self {
features: iter.into_iter().collect(),
bbox: None,
foreign_members: ForeignMembers::new(),
}
}
}
impl<G: Serialize, P: Serialize> Serialize for FeatureCollection<G, P> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut len = 2; if self.bbox.is_some() {
len += 1;
}
len += self.foreign_members.len();
let mut map = serializer.serialize_map(Some(len))?;
map.serialize_entry("type", "FeatureCollection")?;
map.serialize_entry("features", &self.features)?;
if let Some(bbox) = &self.bbox {
map.serialize_entry("bbox", bbox)?;
}
for (name, value) in &self.foreign_members {
map.serialize_entry(name, value)?;
}
map.end()
}
}
enum CollectionKey {
Type,
Features,
Bbox,
Foreign(String),
}
impl<'de> Deserialize<'de> for CollectionKey {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct KeyVisitor;
impl<'de> Visitor<'de> for KeyVisitor {
type Value = CollectionKey;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a GeoJSON FeatureCollection member name")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<CollectionKey, E> {
Ok(match v {
"type" => CollectionKey::Type,
"features" => CollectionKey::Features,
"bbox" => CollectionKey::Bbox,
_ => CollectionKey::Foreign(v.to_owned()),
})
}
}
deserializer.deserialize_str(KeyVisitor)
}
}
impl<'de, G: Deserialize<'de>, P: Deserialize<'de>> Deserialize<'de> for FeatureCollection<G, P> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct CollectionVisitor<G, P>(PhantomData<(G, P)>);
impl<'de, G: Deserialize<'de>, P: Deserialize<'de>> Visitor<'de> for CollectionVisitor<G, P> {
type Value = FeatureCollection<G, P>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a GeoJSON FeatureCollection object")
}
fn visit_map<M: MapAccess<'de>>(
self,
mut map: M,
) -> Result<FeatureCollection<G, P>, M::Error> {
let mut had_type = false;
let mut features: Option<Vec<Feature<G, P>>> = None;
let mut bbox: Option<Bbox> = None;
let mut foreign_members = ForeignMembers::new();
while let Some(key) = map.next_key()? {
match key {
CollectionKey::Type => {
let ty: String = map.next_value()?;
if ty != "FeatureCollection" {
return Err(de::Error::custom(format!(
"expected `type` to be \"FeatureCollection\", found {ty:?}"
)));
}
had_type = true;
}
CollectionKey::Features => features = Some(map.next_value()?),
CollectionKey::Bbox => bbox = map.next_value()?,
CollectionKey::Foreign(name) => {
foreign_members.insert(name, map.next_value()?);
}
}
}
if !had_type {
return Err(de::Error::missing_field("type"));
}
Ok(FeatureCollection {
features: features.ok_or_else(|| de::Error::missing_field("features"))?,
bbox,
foreign_members,
})
}
}
deserializer.deserialize_map(CollectionVisitor(PhantomData))
}
}
impl From<Id> for geojson::feature::Id {
fn from(id: Id) -> Self {
match id {
Id::String(s) => geojson::feature::Id::String(s),
Id::Number(n) => geojson::feature::Id::Number(n),
}
}
}
impl From<geojson::feature::Id> for Id {
fn from(id: geojson::feature::Id) -> Self {
match id {
geojson::feature::Id::String(s) => Id::String(s),
geojson::feature::Id::Number(n) => Id::Number(n),
}
}
}
impl<P: Serialize> TryFrom<Feature<Option<Geometry>, P>> for geojson::Feature {
type Error = serde_json::Error;
fn try_from(f: Feature<Option<Geometry>, P>) -> Result<Self, Self::Error> {
let properties = match serde_json::to_value(&f.properties)? {
serde_json::Value::Object(map) => Some(map),
serde_json::Value::Null => None,
_ => {
return Err(<serde_json::Error as serde::ser::Error>::custom(
"Feature properties must serialize to a JSON object or null",
));
}
};
Ok(geojson::Feature {
bbox: f.bbox.map(Into::into),
geometry: f.geometry.map(geojson::Geometry::try_from).transpose()?,
id: f.id.map(Into::into),
properties,
foreign_members: (!f.foreign_members.is_empty()).then_some(f.foreign_members),
})
}
}
impl<P: serde::de::DeserializeOwned> TryFrom<geojson::Feature> for Feature<Option<Geometry>, P> {
type Error = serde_json::Error;
fn try_from(f: geojson::Feature) -> Result<Self, Self::Error> {
let value = match f.properties {
Some(map) => serde_json::Value::Object(map),
None => serde_json::Value::Null,
};
Ok(Feature {
geometry: f.geometry.map(Geometry::try_from).transpose()?,
properties: serde_json::from_value(value)?,
id: f.id.map(Into::into),
bbox: f.bbox.map(bbox_from_vec).transpose()?,
foreign_members: f.foreign_members.unwrap_or_default(),
})
}
}
#[cfg(feature = "specta")]
pub fn specta_types() -> specta::Types {
specta::Types::default()
.register::<__ts::Feature<Geometry, Geometry>>()
.register::<__ts::FeatureCollection<Geometry, Geometry>>()
.register::<Geometry>()
.register::<Id>()
.register::<Bbox>()
}
#[cfg(feature = "specta")]
#[doc(hidden)]
#[allow(dead_code)]
pub mod __ts {
use serde::{Deserialize, Serialize};
use super::{Bbox, Id};
#[derive(Serialize, Deserialize, specta::Type)]
pub enum FeatureType {
Feature,
}
#[derive(Serialize, Deserialize, specta::Type)]
pub enum FeatureCollectionType {
FeatureCollection,
}
#[derive(Serialize, Deserialize, specta::Type)]
#[serde(rename = "Feature")]
pub struct Feature<G, P> {
#[serde(rename = "type")]
r#type: FeatureType,
geometry: G,
properties: P,
#[specta(type = Id, optional)]
id: Option<Id>,
#[specta(type = Bbox, optional)]
bbox: Option<Bbox>,
}
#[derive(Serialize, Deserialize, specta::Type)]
#[serde(rename = "FeatureCollection")]
pub struct FeatureCollection<G, P> {
#[serde(rename = "type")]
r#type: FeatureCollectionType,
features: Vec<Feature<G, P>>,
#[specta(type = Bbox, optional)]
bbox: Option<Bbox>,
}
}