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