sqlx_postgres/types/geometry/
line_segment.rs1use crate::decode::Decode;
2use crate::encode::{Encode, IsNull};
3use crate::error::BoxDynError;
4use crate::types::Type;
5use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
6use sqlx_core::bytes::Buf;
7use std::str::FromStr;
8
9const ERROR: &str = "error decoding LSEG";
10
11#[doc(alias = "line segment")]
31#[derive(Debug, Clone, PartialEq)]
32pub struct PgLSeg {
33 pub start_x: f64,
34 pub start_y: f64,
35 pub end_x: f64,
36 pub end_y: f64,
37}
38
39impl Type<Postgres> for PgLSeg {
40 fn type_info() -> PgTypeInfo {
41 PgTypeInfo::with_name("lseg")
42 }
43}
44
45impl PgHasArrayType for PgLSeg {
46 fn array_type_info() -> PgTypeInfo {
47 PgTypeInfo::with_name("_lseg")
48 }
49}
50
51impl<'r> Decode<'r, Postgres> for PgLSeg {
52 fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
53 match value.format() {
54 PgValueFormat::Text => Ok(PgLSeg::from_str(value.as_str()?)?),
55 PgValueFormat::Binary => Ok(PgLSeg::from_bytes(value.as_bytes()?)?),
56 }
57 }
58}
59
60impl<'q> Encode<'q, Postgres> for PgLSeg {
61 fn produces(&self) -> Option<PgTypeInfo> {
62 Some(PgTypeInfo::with_name("lseg"))
63 }
64
65 fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
66 self.serialize(buf)?;
67 Ok(IsNull::No)
68 }
69}
70
71impl FromStr for PgLSeg {
72 type Err = BoxDynError;
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 let sanitised = s.replace(['(', ')', '[', ']', ' '], "");
76 let mut parts = sanitised.split(',');
77
78 let start_x = parts
79 .next()
80 .and_then(|s| s.parse::<f64>().ok())
81 .ok_or_else(|| format!("{}: could not get start_x from {}", ERROR, s))?;
82
83 let start_y = parts
84 .next()
85 .and_then(|s| s.parse::<f64>().ok())
86 .ok_or_else(|| format!("{}: could not get start_y from {}", ERROR, s))?;
87
88 let end_x = parts
89 .next()
90 .and_then(|s| s.parse::<f64>().ok())
91 .ok_or_else(|| format!("{}: could not get end_x from {}", ERROR, s))?;
92
93 let end_y = parts
94 .next()
95 .and_then(|s| s.parse::<f64>().ok())
96 .ok_or_else(|| format!("{}: could not get end_y from {}", ERROR, s))?;
97
98 if parts.next().is_some() {
99 return Err(format!("{}: too many numbers inputted in {}", ERROR, s).into());
100 }
101
102 Ok(PgLSeg {
103 start_x,
104 start_y,
105 end_x,
106 end_y,
107 })
108 }
109}
110
111impl PgLSeg {
112 fn from_bytes(mut bytes: &[u8]) -> Result<PgLSeg, BoxDynError> {
113 let start_x = bytes.get_f64();
114 let start_y = bytes.get_f64();
115 let end_x = bytes.get_f64();
116 let end_y = bytes.get_f64();
117
118 Ok(PgLSeg {
119 start_x,
120 start_y,
121 end_x,
122 end_y,
123 })
124 }
125
126 fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), BoxDynError> {
127 buff.extend_from_slice(&self.start_x.to_be_bytes());
128 buff.extend_from_slice(&self.start_y.to_be_bytes());
129 buff.extend_from_slice(&self.end_x.to_be_bytes());
130 buff.extend_from_slice(&self.end_y.to_be_bytes());
131 Ok(())
132 }
133
134 #[cfg(test)]
135 fn serialize_to_vec(&self) -> Vec<u8> {
136 let mut buff = PgArgumentBuffer::default();
137 self.serialize(&mut buff).unwrap();
138 buff.to_vec()
139 }
140}
141
142#[cfg(test)]
143mod lseg_tests {
144
145 use std::str::FromStr;
146
147 use super::PgLSeg;
148
149 const LINE_SEGMENT_BYTES: &[u8] = &[
150 63, 241, 153, 153, 153, 153, 153, 154, 64, 1, 153, 153, 153, 153, 153, 154, 64, 10, 102,
151 102, 102, 102, 102, 102, 64, 17, 153, 153, 153, 153, 153, 154,
152 ];
153
154 #[test]
155 fn can_deserialise_lseg_type_bytes() {
156 let lseg = PgLSeg::from_bytes(LINE_SEGMENT_BYTES).unwrap();
157 assert_eq!(
158 lseg,
159 PgLSeg {
160 start_x: 1.1,
161 start_y: 2.2,
162 end_x: 3.3,
163 end_y: 4.4
164 }
165 )
166 }
167
168 #[test]
169 fn can_deserialise_lseg_type_str_first_syntax() {
170 let lseg = PgLSeg::from_str("[( 1, 2), (3, 4 )]").unwrap();
171 assert_eq!(
172 lseg,
173 PgLSeg {
174 start_x: 1.,
175 start_y: 2.,
176 end_x: 3.,
177 end_y: 4.
178 }
179 );
180 }
181 #[test]
182 fn can_deserialise_lseg_type_str_second_syntax() {
183 let lseg = PgLSeg::from_str("(( 1, 2), (3, 4 ))").unwrap();
184 assert_eq!(
185 lseg,
186 PgLSeg {
187 start_x: 1.,
188 start_y: 2.,
189 end_x: 3.,
190 end_y: 4.
191 }
192 );
193 }
194
195 #[test]
196 fn can_deserialise_lseg_type_str_third_syntax() {
197 let lseg = PgLSeg::from_str("(1, 2), (3, 4 )").unwrap();
198 assert_eq!(
199 lseg,
200 PgLSeg {
201 start_x: 1.,
202 start_y: 2.,
203 end_x: 3.,
204 end_y: 4.
205 }
206 );
207 }
208
209 #[test]
210 fn can_deserialise_lseg_type_str_fourth_syntax() {
211 let lseg = PgLSeg::from_str("1, 2, 3, 4").unwrap();
212 assert_eq!(
213 lseg,
214 PgLSeg {
215 start_x: 1.,
216 start_y: 2.,
217 end_x: 3.,
218 end_y: 4.
219 }
220 );
221 }
222
223 #[test]
224 fn can_deserialise_too_many_numbers() {
225 let input_str = "1, 2, 3, 4, 5";
226 let lseg = PgLSeg::from_str(input_str);
227 assert!(lseg.is_err());
228 if let Err(err) = lseg {
229 assert_eq!(
230 err.to_string(),
231 format!("error decoding LSEG: too many numbers inputted in {input_str}")
232 )
233 }
234 }
235
236 #[test]
237 fn can_deserialise_too_few_numbers() {
238 let input_str = "1, 2, 3";
239 let lseg = PgLSeg::from_str(input_str);
240 assert!(lseg.is_err());
241 if let Err(err) = lseg {
242 assert_eq!(
243 err.to_string(),
244 format!("error decoding LSEG: could not get end_y from {input_str}")
245 )
246 }
247 }
248
249 #[test]
250 fn can_deserialise_invalid_numbers() {
251 let input_str = "1, 2, 3, FOUR";
252 let lseg = PgLSeg::from_str(input_str);
253 assert!(lseg.is_err());
254 if let Err(err) = lseg {
255 assert_eq!(
256 err.to_string(),
257 format!("error decoding LSEG: could not get end_y from {input_str}")
258 )
259 }
260 }
261
262 #[test]
263 fn can_deserialise_lseg_type_str_float() {
264 let lseg = PgLSeg::from_str("(1.1, 2.2), (3.3, 4.4)").unwrap();
265 assert_eq!(
266 lseg,
267 PgLSeg {
268 start_x: 1.1,
269 start_y: 2.2,
270 end_x: 3.3,
271 end_y: 4.4
272 }
273 );
274 }
275
276 #[test]
277 fn can_serialise_lseg_type() {
278 let lseg = PgLSeg {
279 start_x: 1.1,
280 start_y: 2.2,
281 end_x: 3.3,
282 end_y: 4.4,
283 };
284 assert_eq!(lseg.serialize_to_vec(), LINE_SEGMENT_BYTES,)
285 }
286}