postgis_diesel/
multipolygon.rs1use std::fmt::Debug;
2use std::io::Cursor;
3
4#[cfg(feature = "diesel")]
5use crate::{
6 ewkb::{read_ewkb_header, write_ewkb_header},
7 polygon::{read_polygon_body, write_polygon},
8};
9use crate::{
10 ewkb::{EwkbSerializable, GeometryType, BIG_ENDIAN},
11 points::Dimension,
12 types::*,
13};
14use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
15
16use crate::sql_types::*;
17
18impl<T> MultiPolygon<T>
19where
20 T: PointT + Clone,
21{
22 pub fn new(srid: Option<u32>) -> Self {
23 Self::with_capacity(srid, 0)
24 }
25
26 pub fn with_capacity(srid: Option<u32>, cap: usize) -> Self {
27 MultiPolygon {
28 polygons: Vec::with_capacity(cap),
29 srid,
30 }
31 }
32
33 pub fn add_empty_polygon(&mut self) -> &mut Self {
34 self.add_empty_polygon_with_capacity(0)
35 }
36
37 pub fn add_empty_polygon_with_capacity(&mut self, cap: usize) -> &mut Self {
38 self.polygons.push(Polygon {
39 rings: Vec::with_capacity(cap),
40 srid: self.srid,
41 });
42 self
43 }
44
45 pub fn add_point(&mut self, point: T) -> &mut Self {
46 if self.polygons.is_empty() {
47 self.add_empty_polygon();
48 }
49 self.polygons.last_mut().unwrap().add_point(point);
50 self
51 }
52
53 pub fn add_points(&mut self, points: impl IntoIterator<Item = T>) -> &mut Self {
54 if self.polygons.is_empty() {
55 self.add_empty_polygon();
56 }
57 let last = self.polygons.last_mut().unwrap();
58 for point in points {
59 last.add_point(point);
60 }
61 self
62 }
63
64 pub fn dimension(&self) -> u32 {
65 let mut dimension = Dimension::None as u32;
66 if let Some(polygon) = self.polygons.first() {
67 dimension |= polygon.dimension();
68 }
69 dimension
70 }
71}
72
73impl<T> EwkbSerializable for MultiPolygon<T>
74where
75 T: PointT + Clone,
76{
77 fn geometry_type(&self) -> u32 {
78 let mut g_type = GeometryType::MultiPolygon as u32;
79 if let Some(polygon) = self.polygons.first() {
80 g_type |= polygon.dimension();
81 }
82 g_type
83 }
84}
85
86#[cfg(feature = "diesel")]
87impl<T> diesel::serialize::ToSql<Geometry, diesel::pg::Pg> for MultiPolygon<T>
88where
89 T: PointT + Debug + PartialEq + Clone + EwkbSerializable,
90{
91 fn to_sql(
92 &self,
93 out: &mut diesel::serialize::Output<diesel::pg::Pg>,
94 ) -> diesel::serialize::Result {
95 write_multi_polygon(self, self.srid, out)
96 }
97}
98
99#[cfg(feature = "diesel")]
100impl<T> diesel::serialize::ToSql<Geography, diesel::pg::Pg> for MultiPolygon<T>
101where
102 T: PointT + Debug + PartialEq + Clone + EwkbSerializable,
103{
104 fn to_sql(
105 &self,
106 out: &mut diesel::serialize::Output<diesel::pg::Pg>,
107 ) -> diesel::serialize::Result {
108 write_multi_polygon(self, self.srid, out)
109 }
110}
111
112#[cfg(feature = "diesel")]
113impl<T> diesel::deserialize::FromSql<Geometry, diesel::pg::Pg> for MultiPolygon<T>
114where
115 T: PointT + Debug + Clone,
116{
117 fn from_sql(bytes: diesel::pg::PgValue) -> diesel::deserialize::Result<Self> {
118 let mut r = Cursor::new(bytes.as_bytes());
119 let end = r.read_u8()?;
120 if end == BIG_ENDIAN {
121 read_multi_polygon::<BigEndian, T>(&mut r)
122 } else {
123 read_multi_polygon::<LittleEndian, T>(&mut r)
124 }
125 }
126}
127
128#[cfg(feature = "diesel")]
129impl<T> diesel::deserialize::FromSql<Geography, diesel::pg::Pg> for MultiPolygon<T>
130where
131 T: PointT + Debug + Clone,
132{
133 fn from_sql(bytes: diesel::pg::PgValue) -> diesel::deserialize::Result<Self> {
134 diesel::deserialize::FromSql::<Geometry, diesel::pg::Pg>::from_sql(bytes)
135 }
136}
137
138#[cfg(feature = "diesel")]
139pub fn write_multi_polygon<T>(
140 multipolygon: &MultiPolygon<T>,
141 srid: Option<u32>,
142 out: &mut diesel::serialize::Output<diesel::pg::Pg>,
143) -> diesel::serialize::Result
144where
145 T: PointT + EwkbSerializable + Clone,
146{
147 write_ewkb_header(multipolygon, srid, out)?;
148 out.write_u32::<LittleEndian>(multipolygon.polygons.len() as u32)?;
150 for polygon in multipolygon.polygons.iter() {
151 write_polygon(polygon, None, out)?;
152 }
153 Ok(diesel::serialize::IsNull::No)
154}
155
156#[cfg(feature = "diesel")]
157fn read_multi_polygon<T, P>(
158 cursor: &mut Cursor<&[u8]>,
159) -> diesel::deserialize::Result<MultiPolygon<P>>
160where
161 T: byteorder::ByteOrder,
162 P: PointT + Clone,
163{
164 let g_header = read_ewkb_header::<T>(cursor)?.expect(GeometryType::MultiPolygon)?;
165 read_multi_polygon_body::<T, P>(g_header.g_type, g_header.srid, cursor)
166}
167
168#[cfg(feature = "diesel")]
169pub fn read_multi_polygon_body<T, P>(
170 g_type: u32,
171 srid: Option<u32>,
172 cursor: &mut Cursor<&[u8]>,
173) -> diesel::deserialize::Result<MultiPolygon<P>>
174where
175 T: byteorder::ByteOrder,
176 P: PointT + Clone,
177{
178 let polygons_n = cursor.read_u32::<T>()?;
179 let mut polygon = MultiPolygon::with_capacity(srid, polygons_n as usize);
180
181 for _i in 0..polygons_n {
182 cursor.read_u8()?;
184 cursor.read_u32::<T>()?;
185 polygon
186 .polygons
187 .push(read_polygon_body::<T, P>(g_type, srid, cursor)?);
188 }
189 Ok(polygon)
190}