postgis_butmaintained/ewkb/container/
point.rs

1use crate::ewkb::encoding::*;
2use crate::ewkb::point::*;
3use crate::ewkb::{EwkbPoint, EwkbRead, EwkbWrite};
4use crate::{error::Error, types as postgis};
5use byteorder::LittleEndian;
6use byteorder::WriteBytesExt;
7use std::fmt;
8use std::io::{Read, Write};
9use std::iter::FromIterator;
10use std::slice::Iter;
11
12macro_rules! point_container_type {
13    // geometries containing points
14    ($geotypetrait:ident for $geotype:ident) => {
15        /// $geotypetrait
16        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17        #[derive(PartialEq, Clone, Debug)]
18        pub struct $geotype<P: postgis::Point + EwkbRead> {
19            pub points: Vec<P>,
20            pub srid: Option<i32>,
21        }
22
23        impl<P: postgis::Point + EwkbRead> Default for $geotype<P> {
24            fn default() -> Self {
25                Self::new()
26            }
27        }
28
29        impl<P: postgis::Point + EwkbRead> $geotype<P> {
30            pub fn new() -> $geotype<P> {
31                $geotype {
32                    points: Vec::new(),
33                    srid: None,
34                }
35            }
36        }
37
38        impl<P> FromIterator<P> for $geotype<P>
39        where
40            P: postgis::Point + EwkbRead,
41        {
42            #[inline]
43            fn from_iter<I: IntoIterator<Item = P>>(iterable: I) -> $geotype<P> {
44                let iterator = iterable.into_iter();
45                let (lower, _) = iterator.size_hint();
46                let mut ret = $geotype::new();
47                ret.points.reserve(lower);
48                for item in iterator {
49                    ret.points.push(item);
50                }
51                ret
52            }
53        }
54
55        impl<'a, P> postgis::$geotypetrait<'a> for $geotype<P>
56        where
57            P: 'a + postgis::Point + EwkbRead,
58        {
59            type ItemType = P;
60            type Iter = Iter<'a, Self::ItemType>;
61            fn points(&'a self) -> Self::Iter {
62                self.points.iter()
63            }
64        }
65    };
66}
67
68macro_rules! impl_read_for_point_container_type {
69    (singletype $geotype:ident) => {
70        impl<P> EwkbRead for $geotype<P>
71        where
72            P: postgis::Point + EwkbRead,
73        {
74            fn point_type() -> PointType {
75                P::point_type()
76            }
77            fn read_ewkb_body<R: Read>(
78                raw: &mut R,
79                is_be: bool,
80                type_id: u32,
81                srid: Option<i32>,
82            ) -> Result<Self, Error> {
83                let mut points: Vec<P> = vec![];
84                let size = read_u32(raw, is_be)? as usize;
85                for _ in 0..size {
86                    points.push(P::read_ewkb_body(raw, is_be, type_id, srid)?);
87                }
88                Ok($geotype::<P> {
89                    points,
90                    srid,
91                })
92            }
93        }
94    };
95    (multitype $geotype:ident) => {
96        impl<P> EwkbRead for $geotype<P>
97        where
98            P: postgis::Point + EwkbRead,
99        {
100            fn point_type() -> PointType {
101                P::point_type()
102            }
103            fn read_ewkb_body<R: Read>(
104                raw: &mut R,
105                is_be: bool,
106                _type_id: u32,
107                srid: Option<i32>,
108            ) -> Result<Self, Error> {
109                let mut points: Vec<P> = vec![];
110                let size = read_u32(raw, is_be)? as usize;
111                for _ in 0..size {
112                    points.push(P::read_ewkb(raw)?);
113                }
114                Ok($geotype::<P> {
115                    points,
116                    srid,
117                })
118            }
119        }
120    };
121}
122
123macro_rules! point_container_write {
124    ($geotypetrait:ident and $asewkbtype:ident for $geotype:ident to $ewkbtype:ident with type code $typecode:expr, command $writecmd:ident) => {
125        pub struct $ewkbtype<'a, P, I>
126        where
127            P: 'a + postgis::Point,
128            I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
129        {
130            pub geom: &'a dyn postgis::$geotypetrait<'a, ItemType = P, Iter = I>,
131            pub srid: Option<i32>,
132            pub point_type: PointType,
133        }
134
135        pub trait $asewkbtype<'a> {
136            type PointType: 'a + postgis::Point;
137            type Iter: Iterator<Item = &'a Self::PointType>
138                + ExactSizeIterator<Item = &'a Self::PointType>;
139            fn as_ewkb(&'a self) -> $ewkbtype<'a, Self::PointType, Self::Iter>;
140        }
141
142        impl<'a, T, I> fmt::Debug for $ewkbtype<'a, T, I>
143        where
144            T: 'a + postgis::Point,
145            I: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
146        {
147            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148                write!(f, stringify!($ewkbtype))?; //TODO
149                Ok(())
150            }
151        }
152
153        impl<'a, T, I> EwkbWrite for $ewkbtype<'a, T, I>
154        where
155            T: 'a + postgis::Point,
156            I: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
157        {
158            fn opt_srid(&self) -> Option<i32> {
159                self.srid
160            }
161
162            fn type_id(&self) -> u32 {
163                $typecode | Self::wkb_type_id(&self.point_type, self.srid)
164            }
165
166            fn write_ewkb_body<W: Write + ?Sized>(&self, w: &mut W) -> Result<(), Error> {
167                w.write_u32::<LittleEndian>(self.geom.points().len() as u32)?;
168                for geom in self.geom.points() {
169                    let wkb = EwkbPoint {
170                        geom,
171                        srid: None,
172                        point_type: self.point_type.clone(),
173                    };
174                    wkb.$writecmd(w)?;
175                }
176                Ok(())
177            }
178        }
179
180        impl<'a, P> $asewkbtype<'a> for $geotype<P>
181        where
182            P: 'a + postgis::Point + EwkbRead,
183        {
184            type PointType = P;
185            type Iter = Iter<'a, P>;
186            fn as_ewkb(&'a self) -> $ewkbtype<'a, Self::PointType, Self::Iter> {
187                $ewkbtype {
188                    geom: self,
189                    srid: self.srid,
190                    point_type: Self::PointType::point_type(),
191                }
192            }
193        }
194    };
195}
196
197point_container_type!(LineString for LineStringT);
198impl_read_for_point_container_type!(singletype LineStringT);
199point_container_write!(LineString and AsEwkbLineString for LineStringT
200                       to EwkbLineString with type code 0x02,
201                       command write_ewkb_body);
202
203/// OGC LineString type
204pub type LineString = LineStringT<Point>;
205/// OGC LineStringZ type
206pub type LineStringZ = LineStringT<PointZ>;
207/// OGC LineStringM type
208pub type LineStringM = LineStringT<PointM>;
209/// OGC LineStringZM type
210pub type LineStringZM = LineStringT<PointZM>;
211
212point_container_type!(MultiPoint for MultiPointT);
213impl_read_for_point_container_type!(multitype MultiPointT);
214point_container_write!(MultiPoint and AsEwkbMultiPoint for MultiPointT
215                       to EwkbMultiPoint with type code 0x04,
216                       command write_ewkb);
217
218/// OGC MultiPoint type
219pub type MultiPoint = MultiPointT<Point>;
220/// OGC MultiPointZ type
221pub type MultiPointZ = MultiPointT<PointZ>;
222/// OGC MultiPointM type
223pub type MultiPointM = MultiPointT<PointM>;
224/// OGC MultiPointZM type
225pub type MultiPointZM = MultiPointT<PointZM>;