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