postgis_diesel/
multipoint.rs

1use 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    // size and points
129    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        // skip 1 byte for byte order and 4 bytes for point type
160        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}