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