Skip to content

Instantly share code, notes, and snippets.

@insanebaba
Created September 6, 2020 16:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save insanebaba/a15cf1375f4002d7b60b876180e25ab3 to your computer and use it in GitHub Desktop.
Save insanebaba/a15cf1375f4002d7b60b876180e25ab3 to your computer and use it in GitHub Desktop.
GeometryPoint Addition to arysn
use bytes::BytesMut;
// use geo_types::{Coordinate, Point};
use postgres::types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
use serde::ser::{Serialize, SerializeStruct, Serializer};
use std::error::Error;
use std::fmt;
use std::ops::Deref;
use postgis::twkb::Point;
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct GeometryPoint(Point);
impl GeometryPoint {
pub fn new(x: f64, y: f64) -> Self {
GeometryPoint(Point{x,y})
}
}
impl Deref for GeometryPoint {
type Target = Point;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> FromSql<'a> for GeometryPoint {
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
let point: Result<Point, Box<dyn Error + Sync + Send>> = FromSql::from_sql(ty, raw);
point.map(|point| GeometryPoint(point))
}
fn accepts(ty: &Type) -> bool {
<GeometryPoint as FromSql>::accepts(ty)
}
}
impl ToSql for GeometryPoint {
fn to_sql(
&self,
ty: &Type,
out: &mut BytesMut,
) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
ToSql::to_sql(&geo_types::Point::new(self.0.clone().x,self.0.clone().y), ty, out)
}
to_sql_checked!();
fn accepts(ty: &Type) -> bool {
<geo_types::Point<f64> as ToSql>::accepts(ty)
}
}
impl Serialize for GeometryPoint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// 2 is the number of fields in the struct.
let mut state = serializer.serialize_struct("Point", 2)?;
state.serialize_field("x", &self.x)?;
state.serialize_field("y", &self.y)?;
state.end()
}
}
impl<'de> Deserialize<'de> for GeometryPoint {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field {
X,
Y,
};
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`x` or `y` ")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
"x" => Ok(Field::X),
"y" => Ok(Field::Y),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct GeometryPointVisitor;
impl<'de> Visitor<'de> for GeometryPointVisitor {
type Value = GeometryPoint;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct GeometryPoint")
}
fn visit_seq<V>(self, mut seq: V) -> Result<GeometryPoint, V::Error>
where
V: SeqAccess<'de>,
{
let x = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let y = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
Ok(GeometryPoint::new(x, y))
}
fn visit_map<V>(self, mut map: V) -> Result<GeometryPoint, V::Error>
where
V: MapAccess<'de>,
{
let mut x = None;
let mut y = None;
while let Some(key) = map.next_key()? {
match key {
Field::X => {
if x.is_some() {
return Err(de::Error::duplicate_field("x"));
}
x = Some(map.next_value()?);
}
Field::Y => {
if y.is_some() {
return Err(de::Error::duplicate_field("y"));
}
y = Some(map.next_value()?);
}
}
}
let x = x.ok_or_else(|| de::Error::missing_field("x"))?;
let y = y.ok_or_else(|| de::Error::missing_field("y"))?;
Ok(GeometryPoint::new(x, y))
}
}
const FIELDS: &'static [&'static str] = &["x", "y"];
deserializer.deserialize_struct("GeometryPoint", FIELDS, GeometryPoint)
}
}
#[test]
fn test_ser_de() {
let point = Point::new(1.1234, -5.6789, None);
let s = serde_json::to_string(&point).unwrap();
let d: Point = serde_json::from_str(&s).unwrap();
assert_eq!(d, point);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment