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 if g_type & SRID == SRID {
96 srid = Some(cursor.read_u32::<T>()?);
97 }
98 Ok(EwkbHeader { g_type, srid })
99}