1use crate::arguments::XuguArgumentValue;
2use crate::error::BoxDynError;
3use crate::protocol::text::ColumnType;
4use crate::{Xugu, XuguTypeInfo, XuguValueRef};
5use byteorder::{BigEndian, ByteOrder};
6use sqlx_core::decode::Decode;
7use sqlx_core::encode::{Encode, IsNull};
8use sqlx_core::types::Type;
9use std::borrow::Cow;
10
11fn real_compatible(ty: &XuguTypeInfo) -> bool {
12 matches!(ty.r#type, ColumnType::FLOAT | ColumnType::DOUBLE)
14}
15
16impl Type<Xugu> for f32 {
17 fn type_info() -> XuguTypeInfo {
18 XuguTypeInfo::binary(ColumnType::FLOAT)
19 }
20
21 fn compatible(ty: &XuguTypeInfo) -> bool {
22 real_compatible(ty)
23 }
24}
25
26impl Type<Xugu> for f64 {
27 fn type_info() -> XuguTypeInfo {
28 XuguTypeInfo::binary(ColumnType::DOUBLE)
29 }
30
31 fn compatible(ty: &XuguTypeInfo) -> bool {
32 real_compatible(ty)
33 }
34}
35
36impl Encode<'_, Xugu> for f32 {
37 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
38 let buf = self.to_be_bytes().to_vec();
39 args.push(XuguArgumentValue::Bin(Cow::Owned(buf)));
40
41 Ok(IsNull::No)
42 }
43}
44
45impl Encode<'_, Xugu> for f64 {
46 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
47 let buf = self.to_be_bytes().to_vec();
48 args.push(XuguArgumentValue::Bin(Cow::Owned(buf)));
49
50 Ok(IsNull::No)
51 }
52}
53
54impl Decode<'_, Xugu> for f32 {
55 fn decode(value: XuguValueRef<'_>) -> Result<Self, BoxDynError> {
56 let buf = value.as_bytes()?;
57
58 Ok(match buf.len() {
59 4 => BigEndian::read_f32(buf),
61 #[allow(clippy::cast_possible_truncation)]
64 8 => BigEndian::read_f64(buf) as f32,
65 other => {
66 return Err(format!(
69 "expected a FLOAT as 4 or 8 bytes, got {other} bytes; \
70 note that decoding DECIMAL as `f32` is not supported \
71 due to differing semantics"
72 )
73 .into());
74 }
75 })
76 }
77}
78
79impl Decode<'_, Xugu> for f64 {
80 fn decode(value: XuguValueRef<'_>) -> Result<Self, BoxDynError> {
81 let buf = value.as_bytes()?;
82
83 Ok(match buf.len() {
85 4 => BigEndian::read_f32(buf) as f64,
87 8 => BigEndian::read_f64(buf),
88 other => {
89 return Err(format!(
92 "expected a DOUBLE as 4 or 8 bytes, got {other} bytes; \
93 note that decoding DECIMAL as `f64` is not supported \
94 due to differing semantics"
95 )
96 .into());
97 }
98 })
99 }
100}