sqlx_xugu/types/geometry/
point.rs1use crate::arguments::XuguArgumentValue;
2use crate::protocol::text::ColumnType;
3use crate::{Xugu, XuguTypeInfo, XuguValueRef};
4use bytes::Buf;
5use sqlx_core::decode::Decode;
6use sqlx_core::encode::{Encode, IsNull};
7use sqlx_core::error::BoxDynError;
8use sqlx_core::types::Type;
9use sqlx_core::Error;
10use std::borrow::Cow;
11use std::fmt::{Display, Formatter};
12use std::str::FromStr;
13
14#[derive(Debug, Clone, PartialEq)]
27pub struct XgPoint {
28 pub x: f64,
29 pub y: f64,
30}
31
32impl Type<Xugu> for XgPoint {
33 fn type_info() -> XuguTypeInfo {
34 XuguTypeInfo::binary(ColumnType::POINT)
35 }
36
37 fn compatible(ty: &XuguTypeInfo) -> bool {
38 matches!(
39 ty.r#type,
40 ColumnType::CHAR | ColumnType::POINT | ColumnType::POINT_OLD
41 )
42 }
43}
44
45impl Encode<'_, Xugu> for XgPoint {
46 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue>) -> Result<IsNull, BoxDynError> {
47 let s = self.to_string();
48
49 args.push(XuguArgumentValue::Str(Cow::Owned(s)));
50
51 Ok(IsNull::No)
52 }
53
54 fn produces(&self) -> Option<XuguTypeInfo> {
55 Some(XuguTypeInfo::binary(ColumnType::CHAR))
56 }
57}
58
59impl<'r> Decode<'r, Xugu> for XgPoint {
60 fn decode(value: XuguValueRef<'r>) -> Result<Self, BoxDynError> {
61 let ty = value.type_info.r#type;
62 if ty == ColumnType::POINT_OLD {
63 let buf = value.as_bytes()?;
64 return Ok(Self::from_bytes(buf)?);
65 }
66 if ty == ColumnType::POINT {
68 let buf = value.as_bytes()?;
69 if buf.len() == 16 && buf[0] != b'(' && !buf.contains(&b',') {
70 return Ok(Self::from_bytes(buf)?);
71 }
72 }
73
74 let s = value.as_str()?;
75 Ok(Self::from_str(s)?)
76 }
77}
78
79fn parse_float_from_str(s: &str, error_msg: &str) -> Result<f64, Error> {
80 s.trim()
81 .parse()
82 .map_err(|_| Error::Decode(error_msg.into()))
83}
84
85impl Display for XgPoint {
86 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
87 write!(f, "({},{})", self.x, self.y)
88 }
89}
90
91impl FromStr for XgPoint {
92 type Err = BoxDynError;
93
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 let (x_str, y_str) = s
96 .trim_matches(|c| c == '(' || c == ')' || c == ' ')
97 .split_once(',')
98 .ok_or_else(|| {
99 format!(
100 "[E50044]error decoding POINT: could not get x and y from {}",
101 s
102 )
103 })?;
104
105 let x = parse_float_from_str(x_str, "[E50044]error decoding POINT: could not get x")?;
106 let y = parse_float_from_str(y_str, "[E50044]error decoding POINT: could not get y")?;
107
108 Ok(Self { x, y })
109 }
110}
111
112impl XgPoint {
113 pub fn from_bytes(mut bytes: &[u8]) -> Result<Self, BoxDynError> {
114 let x = bytes.get_f64();
115 let y = bytes.get_f64();
116 Ok(Self { x, y })
117 }
118}