use std::fmt;
use crate::sql_types::Geography;
use crate::sql_types::Geometry;
#[derive(Debug, Clone, PartialEq)]
pub struct PointConstructorError {
pub reason: String,
}
impl fmt::Display for PointConstructorError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "can't construct point: {}", self.reason)
}
}
impl std::error::Error for PointConstructorError {}
#[derive(Copy, Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point {
pub x: f64,
pub y: f64,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[derive(Copy, Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PointZ {
pub x: f64,
pub y: f64,
pub z: f64,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[derive(Copy, Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PointM {
pub x: f64,
pub y: f64,
pub m: f64,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[derive(Copy, Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PointZM {
pub x: f64,
pub y: f64,
pub z: f64,
pub m: f64,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
pub trait PointT {
fn new_point(
x: f64,
y: f64,
srid: Option<u32>,
z: Option<f64>,
m: Option<f64>,
) -> Result<Self, PointConstructorError>
where
Self: Sized;
fn get_x(&self) -> f64;
fn get_y(&self) -> f64;
fn get_srid(&self) -> Option<u32>;
fn get_z(&self) -> Option<f64>;
fn get_m(&self) -> Option<f64>;
fn dimension(&self) -> u32;
}
#[derive(Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MultiPoint<T> {
pub points: Vec<T>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[derive(Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct LineString<T> {
pub points: Vec<T>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[derive(Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MultiLineString<T> {
pub lines: Vec<LineString<T>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[derive(Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Polygon<T> {
pub rings: Vec<Vec<T>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[derive(Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MultiPolygon<T> {
pub polygons: Vec<Polygon<T>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[derive(Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde_geojson", derive(Deserialize))]
#[cfg_attr(feature = "serde_geojson", serde(tag = "type", bound(deserialize = "T: crate::geojson::GeoJsonGeometry<f64> + PointT + Clone + serde::Deserialize<'de>")))]
pub enum GeometryContainer<T> {
Point(T),
LineString(LineString<T>),
Polygon(Polygon<T>),
MultiPoint(MultiPoint<T>),
MultiLineString(MultiLineString<T>),
MultiPolygon(MultiPolygon<T>),
GeometryCollection(GeometryCollection<T>),
}
#[derive(Clone, Debug, PartialEq, FromSqlRow, AsExpression)]
#[diesel(sql_type = Geometry)]
#[diesel(sql_type = Geography)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GeometryCollection<T> {
pub geometries: Vec<GeometryContainer<T>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub srid: Option<u32>,
}
#[cfg(feature = "serde_geojson")]
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(tag = "type", bound(deserialize = "T: crate::geojson::GeoJsonGeometry<f64> + PointT + Clone + serde::Deserialize<'de>, P: serde::Deserialize<'de>"))]
pub struct Feature<T, P: serde::Serialize> {
pub id: Option<String>,
pub geometry: Option<GeometryContainer<T>>,
pub properties: Option<P>,
}
#[cfg(feature = "serde_geojson")]
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(tag = "type", bound(deserialize = "T: crate::geojson::GeoJsonGeometry<f64> + PointT + Clone + serde::Deserialize<'de>, P: serde::Deserialize<'de>"))]
pub struct FeatureCollection<T, P: serde::Serialize> {
pub features: Vec<Feature<T, P>>,
}
#[cfg(test)]
#[cfg(feature = "serde")]
mod tests {
use super::*;
#[test]
fn test_point_serde() {
let point = Point::new(72.0, 64.0, None);
let expected_point = "{\"x\":72.0,\"y\":64.0}";
let point_from_json = serde_json::from_str(expected_point).unwrap();
assert_eq!(point, point_from_json);
let point_json = serde_json::to_string(&point).unwrap();
assert_eq!(expected_point, point_json);
}
}