postgis_diesel/
ewkb.rs

1use std::io::Cursor;
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4
5#[derive(Debug, PartialEq)]
6pub enum GeometryType {
7    Point = 1,
8    LineString,
9    Polygon,
10    MultiPoint,
11    MultiLineString,
12    MultiPolygon,
13    GeometryCollection,
14}
15
16pub const SRID: u32 = 0x20000000;
17pub const LITTLE_ENDIAN: u8 = 1;
18pub const BIG_ENDIAN: u8 = 0;
19
20impl From<u32> for GeometryType {
21    fn from(t: u32) -> Self {
22        if t & 7 == 7 {
23            return Self::GeometryCollection;
24        } else if t & 6 == 6 {
25            return Self::MultiPolygon;
26        } else if t & 5 == 5 {
27            return Self::MultiLineString;
28        } else if t & 4 == 4 {
29            return Self::MultiPoint;
30        } else if t & 3 == 3 {
31            return Self::Polygon;
32        } else if t & 2 == 2 {
33            return Self::LineString;
34        } else {
35            return Self::Point;
36        }
37    }
38}
39
40pub trait EwkbSerializable {
41    fn geometry_type(&self) -> u32;
42}
43
44#[cfg(feature = "diesel")]
45pub fn write_ewkb_header<T>(
46    geometry: &T,
47    srid: Option<u32>,
48    out: &mut diesel::serialize::Output<diesel::pg::Pg>,
49) -> diesel::serialize::Result
50where
51    T: EwkbSerializable,
52{
53    out.write_u8(LITTLE_ENDIAN)?;
54    let mut p_type = geometry.geometry_type();
55    match srid {
56        Some(srid) => {
57            p_type |= SRID;
58            out.write_u32::<LittleEndian>(p_type)?;
59            out.write_u32::<LittleEndian>(srid)?;
60        }
61        None => out.write_u32::<LittleEndian>(p_type)?,
62    }
63    Ok(diesel::serialize::IsNull::No)
64}
65
66pub struct EwkbHeader {
67    pub g_type: u32,
68    pub srid: Option<u32>,
69}
70
71impl EwkbHeader {
72    #[cfg(feature = "diesel")]
73    pub fn expect(self, expected_type: GeometryType) -> diesel::deserialize::Result<Self> {
74        if GeometryType::from(self.g_type) != expected_type {
75            return Err(format!(
76                "Geometry {:?} is not a {:?}",
77                GeometryType::from(self.g_type),
78                expected_type
79            )
80            .into());
81        } else {
82            Ok(self)
83        }
84    }
85}
86
87#[cfg(feature = "diesel")]
88pub fn read_ewkb_header<T>(cursor: &mut Cursor<&[u8]>) -> diesel::deserialize::Result<EwkbHeader>
89where
90    T: byteorder::ByteOrder,
91{
92    let g_type = cursor.read_u32::<T>()?;
93    let mut srid = None;
94    // SRID included
95    if g_type & SRID == SRID {
96        srid = Some(cursor.read_u32::<T>()?);
97    }
98    Ok(EwkbHeader { g_type, srid })
99}