sqlx_xugu/types/geometry/
circle.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
14const ERROR: &str = "[E50044]error decoding CIRCLE";
15
16#[derive(Debug, Clone, PartialEq)]
30pub struct XgCircle {
31 pub x: f64,
32 pub y: f64,
33 pub radius: f64,
34}
35
36impl Type<Xugu> for XgCircle {
37 fn type_info() -> XuguTypeInfo {
38 XuguTypeInfo::binary(ColumnType::CIRCLE)
39 }
40
41 fn compatible(ty: &XuguTypeInfo) -> bool {
42 matches!(ty.r#type, ColumnType::CHAR | ColumnType::CIRCLE)
43 }
44}
45
46impl<'r> Decode<'r, Xugu> for XgCircle {
47 fn decode(value: XuguValueRef<'r>) -> Result<Self, BoxDynError> {
48 let s = value.as_str()?;
49 Ok(Self::from_str(s)?)
50 }
51}
52
53impl Encode<'_, Xugu> for XgCircle {
54 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue>) -> Result<IsNull, BoxDynError> {
55 let s = self.to_string();
56
57 args.push(XuguArgumentValue::Str(Cow::Owned(s)));
58
59 Ok(IsNull::No)
60 }
61
62 fn produces(&self) -> Option<XuguTypeInfo> {
63 Some(XuguTypeInfo::binary(ColumnType::CHAR))
64 }
65}
66
67impl Display for XgCircle {
68 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
69 write!(f, "<({},{}),{}>", self.x, self.y, self.radius)
70 }
71}
72
73impl FromStr for XgCircle {
74 type Err = BoxDynError;
75
76 fn from_str(s: &str) -> Result<Self, Self::Err> {
77 let sanitised = s.replace(['<', '>', '(', ')', ' '], "");
78 let mut parts = sanitised.split(',');
79
80 let x = parts
81 .next()
82 .and_then(|s| s.trim().parse::<f64>().ok())
83 .ok_or_else(|| format!("{}: could not get x from {}", ERROR, s))?;
84
85 let y = parts
86 .next()
87 .and_then(|s| s.trim().parse::<f64>().ok())
88 .ok_or_else(|| format!("{}: could not get y from {}", ERROR, s))?;
89
90 let radius = parts
91 .next()
92 .and_then(|s| s.trim().parse::<f64>().ok())
93 .ok_or_else(|| format!("{}: could not get radius from {}", ERROR, s))?;
94
95 if parts.next().is_some() {
96 return Err(format!("{}: too many numbers inputted in {}", ERROR, s).into());
97 }
98
99 if radius < 0. {
100 return Err(format!("{}: cannot have negative radius: {}", ERROR, s).into());
101 }
102
103 Ok(XgCircle { x, y, radius })
104 }
105}
106
107impl XgCircle {
108 pub fn from_bytes(mut bytes: &[u8]) -> Result<XgCircle, Error> {
109 let x = bytes.get_f64();
110 let y = bytes.get_f64();
111 let r = bytes.get_f64();
112 Ok(XgCircle { x, y, radius: r })
113 }
114}