postgis_diesel 2.4.0

An extension for Diesel framework to support PostGIS geometry datatype.
Documentation
use std::fmt::Debug;
use std::io::Cursor;

use crate::{
    ewkb::{read_ewkb_header, EwkbSerializable, GeometryType, BIG_ENDIAN},
    geometrycollection::{read_geometry_collection_body, write_geometry_collection},
    linestring::{read_linestring_body, write_linestring},
    multiline::{read_multiline_body, write_multiline},
    multipoint::{read_multi_point_body, write_multi_point},
    multipolygon::{read_multi_polygon_body, write_multi_polygon},
    points::{read_point_coordinates, write_point},
    polygon::*,
    sql_types::{Geography, Geometry},
    types::*,
};
use byteorder::{BigEndian, LittleEndian};
use diesel::{
    deserialize::{self, FromSql},
    pg::{self, Pg},
    serialize::{self, Output, ToSql},
};

impl<T> GeometryContainer<T>
where
    T: PointT + Clone,
{
    pub fn dimension(&self) -> u32 {
        match self {
            GeometryContainer::Point(g) => g.dimension(),
            GeometryContainer::LineString(g) => g.dimension(),
            GeometryContainer::Polygon(g) => g.dimension(),
            GeometryContainer::MultiPoint(g) => g.dimension(),
            GeometryContainer::MultiLineString(g) => g.dimension(),
            GeometryContainer::MultiPolygon(g) => g.dimension(),
            GeometryContainer::GeometryCollection(g) => g.dimension(),
        }
    }
}

impl<T> ToSql<Geometry, Pg> for GeometryContainer<T>
where
    T: PointT + Debug + PartialEq + Clone + EwkbSerializable + ToSql<Geometry, Pg>,
{
    fn to_sql(&self, out: &mut Output<Pg>) -> serialize::Result {
        match self {
            GeometryContainer::Point(g) => write_point(g, g.get_srid(), out),
            GeometryContainer::MultiPoint(g) => write_multi_point(g, g.srid, out),
            GeometryContainer::LineString(g) => write_linestring(g, g.srid, out),
            GeometryContainer::MultiLineString(g) => write_multiline(g, g.srid, out),
            GeometryContainer::Polygon(g) => write_polygon(g, g.srid, out),
            GeometryContainer::MultiPolygon(g) => write_multi_polygon(g, g.srid, out),
            GeometryContainer::GeometryCollection(g) => write_geometry_collection(g, g.srid, out),
        }
    }
}

impl<T> ToSql<Geography, Pg> for GeometryContainer<T>
where
    T: PointT + Debug + PartialEq + Clone + EwkbSerializable + ToSql<Geometry, Pg>,
{
    fn to_sql(&self, out: &mut Output<Pg>) -> serialize::Result {
        match self {
            GeometryContainer::Point(g) => write_point(g, g.get_srid(), out),
            GeometryContainer::MultiPoint(g) => write_multi_point(g, g.srid, out),
            GeometryContainer::LineString(g) => write_linestring(g, g.srid, out),
            GeometryContainer::MultiLineString(g) => write_multiline(g, g.srid, out),
            GeometryContainer::Polygon(g) => write_polygon(g, g.srid, out),
            GeometryContainer::MultiPolygon(g) => write_multi_polygon(g, g.srid, out),
            GeometryContainer::GeometryCollection(g) => write_geometry_collection(g, g.srid, out),
        }
    }
}

impl<T> FromSql<Geometry, Pg> for GeometryContainer<T>
where
    T: PointT + Debug + Clone + FromSql<Geometry, Pg>,
{
    fn from_sql(bytes: pg::PgValue) -> deserialize::Result<Self> {
        use byteorder::ReadBytesExt;

        let mut cursor = Cursor::new(bytes.as_bytes());
        let end = cursor.read_u8()?;
        let container = if end == BIG_ENDIAN {
            let g_header = read_ewkb_header::<BigEndian>(&mut cursor)?;
            match GeometryType::from(g_header.g_type) {
                GeometryType::Point => {
                    GeometryContainer::Point(read_point_coordinates::<BigEndian, T>(
                        &mut cursor,
                        g_header.g_type,
                        g_header.srid,
                    )?)
                }
                GeometryType::MultiPoint => {
                    GeometryContainer::MultiPoint(read_multi_point_body::<BigEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::LineString => {
                    GeometryContainer::LineString(read_linestring_body::<BigEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::MultiLineString => {
                    GeometryContainer::MultiLineString(read_multiline_body::<BigEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::Polygon => {
                    GeometryContainer::Polygon(read_polygon_body::<BigEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::MultiPolygon => {
                    GeometryContainer::MultiPolygon(read_multi_polygon_body::<BigEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::GeometryCollection => {
                    GeometryContainer::GeometryCollection(read_geometry_collection_body::<
                        BigEndian,
                        T,
                    >(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
            }
        } else {
            let g_header = read_ewkb_header::<LittleEndian>(&mut cursor)?;
            match GeometryType::from(g_header.g_type) {
                GeometryType::Point => {
                    GeometryContainer::Point(read_point_coordinates::<LittleEndian, T>(
                        &mut cursor,
                        g_header.g_type,
                        g_header.srid,
                    )?)
                }
                GeometryType::MultiPoint => {
                    GeometryContainer::MultiPoint(read_multi_point_body::<LittleEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::LineString => {
                    GeometryContainer::LineString(read_linestring_body::<LittleEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::MultiLineString => {
                    GeometryContainer::MultiLineString(read_multiline_body::<LittleEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::Polygon => {
                    GeometryContainer::Polygon(read_polygon_body::<LittleEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::MultiPolygon => {
                    GeometryContainer::MultiPolygon(read_multi_polygon_body::<LittleEndian, T>(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
                GeometryType::GeometryCollection => {
                    GeometryContainer::GeometryCollection(read_geometry_collection_body::<
                        LittleEndian,
                        T,
                    >(
                        g_header.g_type,
                        g_header.srid,
                        &mut cursor,
                    )?)
                }
            }
        };
        Ok(container)
    }
}

impl<T> FromSql<Geography, Pg> for GeometryContainer<T>
where
    T: PointT + Debug + Clone + FromSql<Geometry, Pg>,
{
    fn from_sql(bytes: pg::PgValue) -> deserialize::Result<Self> {
        FromSql::<Geometry, Pg>::from_sql(bytes)
    }
}