sqlx_postgres/types/geometry/
line.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 LINE";
10
11#[derive(Debug, Clone, PartialEq)]
20pub struct PgLine {
21 pub a: f64,
22 pub b: f64,
23 pub c: f64,
24}
25
26impl Type<Postgres> for PgLine {
27 fn type_info() -> PgTypeInfo {
28 PgTypeInfo::with_name("line")
29 }
30}
31
32impl PgHasArrayType for PgLine {
33 fn array_type_info() -> PgTypeInfo {
34 PgTypeInfo::with_name("_line")
35 }
36}
37
38impl<'r> Decode<'r, Postgres> for PgLine {
39 fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
40 match value.format() {
41 PgValueFormat::Text => Ok(PgLine::from_str(value.as_str()?)?),
42 PgValueFormat::Binary => Ok(PgLine::from_bytes(value.as_bytes()?)?),
43 }
44 }
45}
46
47impl<'q> Encode<'q, Postgres> for PgLine {
48 fn produces(&self) -> Option<PgTypeInfo> {
49 Some(PgTypeInfo::with_name("line"))
50 }
51
52 fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
53 self.serialize(buf)?;
54 Ok(IsNull::No)
55 }
56}
57
58impl FromStr for PgLine {
59 type Err = BoxDynError;
60
61 fn from_str(s: &str) -> Result<Self, Self::Err> {
62 let mut parts = s
63 .trim_matches(|c| c == '{' || c == '}' || c == ' ')
64 .split(',');
65
66 let a = parts
67 .next()
68 .and_then(|s| s.trim().parse::<f64>().ok())
69 .ok_or_else(|| format!("{}: could not get a from {}", ERROR, s))?;
70
71 let b = parts
72 .next()
73 .and_then(|s| s.trim().parse::<f64>().ok())
74 .ok_or_else(|| format!("{}: could not get b from {}", ERROR, s))?;
75
76 let c = parts
77 .next()
78 .and_then(|s| s.trim().parse::<f64>().ok())
79 .ok_or_else(|| format!("{}: could not get c from {}", ERROR, s))?;
80
81 if parts.next().is_some() {
82 return Err(format!("{}: too many numbers inputted in {}", ERROR, s).into());
83 }
84
85 Ok(PgLine { a, b, c })
86 }
87}
88
89impl PgLine {
90 fn from_bytes(mut bytes: &[u8]) -> Result<PgLine, BoxDynError> {
91 let a = bytes.get_f64();
92 let b = bytes.get_f64();
93 let c = bytes.get_f64();
94 Ok(PgLine { a, b, c })
95 }
96
97 fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), BoxDynError> {
98 buff.extend_from_slice(&self.a.to_be_bytes());
99 buff.extend_from_slice(&self.b.to_be_bytes());
100 buff.extend_from_slice(&self.c.to_be_bytes());
101 Ok(())
102 }
103
104 #[cfg(test)]
105 fn serialize_to_vec(&self) -> Vec<u8> {
106 let mut buff = PgArgumentBuffer::default();
107 self.serialize(&mut buff).unwrap();
108 buff.to_vec()
109 }
110}
111
112#[cfg(test)]
113mod line_tests {
114
115 use std::str::FromStr;
116
117 use super::PgLine;
118
119 const LINE_BYTES: &[u8] = &[
120 63, 241, 153, 153, 153, 153, 153, 154, 64, 1, 153, 153, 153, 153, 153, 154, 64, 10, 102,
121 102, 102, 102, 102, 102,
122 ];
123
124 #[test]
125 fn can_deserialise_line_type_bytes() {
126 let line = PgLine::from_bytes(LINE_BYTES).unwrap();
127 assert_eq!(
128 line,
129 PgLine {
130 a: 1.1,
131 b: 2.2,
132 c: 3.3
133 }
134 )
135 }
136
137 #[test]
138 fn can_deserialise_line_type_str() {
139 let line = PgLine::from_str("{ 1, 2, 3 }").unwrap();
140 assert_eq!(
141 line,
142 PgLine {
143 a: 1.0,
144 b: 2.0,
145 c: 3.0
146 }
147 );
148 }
149
150 #[test]
151 fn cannot_deserialise_line_too_few_numbers() {
152 let input_str = "{ 1, 2 }";
153 let line = PgLine::from_str(input_str);
154 assert!(line.is_err());
155 if let Err(err) = line {
156 assert_eq!(
157 err.to_string(),
158 format!("error decoding LINE: could not get c from {input_str}")
159 )
160 }
161 }
162
163 #[test]
164 fn cannot_deserialise_line_too_many_numbers() {
165 let input_str = "{ 1, 2, 3, 4 }";
166 let line = PgLine::from_str(input_str);
167 assert!(line.is_err());
168 if let Err(err) = line {
169 assert_eq!(
170 err.to_string(),
171 format!("error decoding LINE: too many numbers inputted in {input_str}")
172 )
173 }
174 }
175
176 #[test]
177 fn cannot_deserialise_line_invalid_numbers() {
178 let input_str = "{ 1, 2, three }";
179 let line = PgLine::from_str(input_str);
180 assert!(line.is_err());
181 if let Err(err) = line {
182 assert_eq!(
183 err.to_string(),
184 format!("error decoding LINE: could not get c from {input_str}")
185 )
186 }
187 }
188
189 #[test]
190 fn can_deserialise_line_type_str_float() {
191 let line = PgLine::from_str("{1.1, 2.2, 3.3}").unwrap();
192 assert_eq!(
193 line,
194 PgLine {
195 a: 1.1,
196 b: 2.2,
197 c: 3.3
198 }
199 );
200 }
201
202 #[test]
203 fn can_serialise_line_type() {
204 let line = PgLine {
205 a: 1.1,
206 b: 2.2,
207 c: 3.3,
208 };
209 assert_eq!(line.serialize_to_vec(), LINE_BYTES,)
210 }
211}