diesel/mysql/types/
primitives.rs1use crate::Queryable;
2#[cfg(feature = "mysql_backend")]
3use crate::deserialize::FromSqlRef;
4use crate::deserialize::{self, FromSql};
5use crate::mysql::{Mysql, MysqlValue, NumericRepresentation};
6use crate::result::Error::DeserializationError;
7use crate::sql_types::{BigInt, Binary, Double, Float, Integer, SmallInt, Text};
8use core::error::Error;
9use core::str::{self, FromStr};
10
11fn decimal_to_integer<T>(bytes: &[u8]) -> deserialize::Result<T>
12where
13 T: FromStr,
14 T::Err: Error + Send + Sync + 'static,
15{
16 let string = str::from_utf8(bytes)?;
17 let mut split = string.split('.');
18 let integer_portion = split.next().unwrap_or_default();
19 let _decimal_portion = split.next().unwrap_or_default();
20 if split.next().is_some() {
21 Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Invalid decimal format: {0:?}",
string))
})format!("Invalid decimal format: {string:?}").into())
22 } else {
23 Ok(integer_portion.parse()?)
24 }
25}
26
27#[allow(clippy::cast_possible_truncation)] fn f32_to_i64(f: f32) -> deserialize::Result<i64> {
29 if f <= i64::MAX as f32 && f >= i64::MIN as f32 {
30 Ok(f.trunc() as i64)
31 } else {
32 Err(Box::new(DeserializationError(
33 "Numeric overflow/underflow occurred".into(),
34 )) as _)
35 }
36}
37
38#[allow(clippy::cast_possible_truncation)] fn f64_to_i64(f: f64) -> deserialize::Result<i64> {
40 if f <= i64::MAX as f64 && f >= i64::MIN as f64 {
41 Ok(f.trunc() as i64)
42 } else {
43 Err(Box::new(DeserializationError(
44 "Numeric overflow/underflow occurred".into(),
45 )) as _)
46 }
47}
48
49#[cfg(feature = "mysql_backend")]
50impl FromSql<SmallInt, Mysql> for i16 {
51 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
52 match value.numeric_value()? {
53 NumericRepresentation::Tiny(x) => Ok(x.into()),
54 NumericRepresentation::Small(x) => Ok(x),
55 NumericRepresentation::Medium(x) => x.try_into().map_err(|_| {
56 Box::new(DeserializationError(
57 "Numeric overflow/underflow occurred".into(),
58 )) as _
59 }),
60 NumericRepresentation::Big(x) => x.try_into().map_err(|_| {
61 Box::new(DeserializationError(
62 "Numeric overflow/underflow occurred".into(),
63 )) as _
64 }),
65 NumericRepresentation::Float(x) => f32_to_i64(x)?.try_into().map_err(|_| {
66 Box::new(DeserializationError(
67 "Numeric overflow/underflow occurred".into(),
68 )) as _
69 }),
70 NumericRepresentation::Double(x) => f64_to_i64(x)?.try_into().map_err(|_| {
71 Box::new(DeserializationError(
72 "Numeric overflow/underflow occurred".into(),
73 )) as _
74 }),
75 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
76 }
77 }
78}
79
80#[cfg(feature = "mysql_backend")]
81impl FromSql<Integer, Mysql> for i32 {
82 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
83 match value.numeric_value()? {
84 NumericRepresentation::Tiny(x) => Ok(x.into()),
85 NumericRepresentation::Small(x) => Ok(x.into()),
86 NumericRepresentation::Medium(x) => Ok(x),
87 NumericRepresentation::Big(x) => x.try_into().map_err(|_| {
88 Box::new(DeserializationError(
89 "Numeric overflow/underflow occurred".into(),
90 )) as _
91 }),
92 NumericRepresentation::Float(x) => f32_to_i64(x).and_then(|i| {
93 i.try_into().map_err(|_| {
94 Box::new(DeserializationError(
95 "Numeric overflow/underflow occurred".into(),
96 )) as _
97 })
98 }),
99 NumericRepresentation::Double(x) => f64_to_i64(x).and_then(|i| {
100 i.try_into().map_err(|_| {
101 Box::new(DeserializationError(
102 "Numeric overflow/underflow occurred".into(),
103 )) as _
104 })
105 }),
106 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
107 }
108 }
109}
110
111#[cfg(feature = "mysql_backend")]
112impl FromSql<BigInt, Mysql> for i64 {
113 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
114 match value.numeric_value()? {
115 NumericRepresentation::Tiny(x) => Ok(x.into()),
116 NumericRepresentation::Small(x) => Ok(x.into()),
117 NumericRepresentation::Medium(x) => Ok(x.into()),
118 NumericRepresentation::Big(x) => Ok(x),
119 NumericRepresentation::Float(x) => f32_to_i64(x),
120 NumericRepresentation::Double(x) => f64_to_i64(x),
121 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
122 }
123 }
124}
125
126#[cfg(feature = "mysql_backend")]
127impl FromSql<Float, Mysql> for f32 {
128 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
129 match value.numeric_value()? {
130 NumericRepresentation::Tiny(x) => Ok(x.into()),
131 NumericRepresentation::Small(x) => Ok(x.into()),
132 NumericRepresentation::Medium(x) => Ok(x as Self),
133 NumericRepresentation::Big(x) => Ok(x as Self),
134 NumericRepresentation::Float(x) => Ok(x),
135 #[allow(clippy::cast_possible_truncation)]
137 NumericRepresentation::Double(x) => Ok(x as Self),
138 NumericRepresentation::Decimal(bytes) => Ok(str::from_utf8(bytes)?.parse()?),
139 }
140 }
141}
142
143#[cfg(feature = "mysql_backend")]
144impl FromSql<Double, Mysql> for f64 {
145 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
146 match value.numeric_value()? {
147 NumericRepresentation::Tiny(x) => Ok(x.into()),
148 NumericRepresentation::Small(x) => Ok(x.into()),
149 NumericRepresentation::Medium(x) => Ok(x.into()),
150 NumericRepresentation::Big(x) => Ok(x as Self),
151 NumericRepresentation::Float(x) => Ok(x.into()),
152 NumericRepresentation::Double(x) => Ok(x),
153 NumericRepresentation::Decimal(bytes) => Ok(str::from_utf8(bytes)?.parse()?),
154 }
155 }
156}
157
158#[cfg(feature = "mysql_backend")]
164impl FromSql<Text, Mysql> for *const str {
165 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
166 let string = str::from_utf8(value.as_bytes())?;
167 Ok(string as *const str)
168 }
169}
170
171#[cfg(feature = "mysql_backend")]
172impl<'a> FromSqlRef<'a, Text, Mysql> for &'a str {
173 fn from_sql(bytes: MysqlValue<'a>) -> deserialize::Result<Self> {
174 let string = str::from_utf8(bytes.as_bytes())?;
175 Ok(string)
176 }
177}
178
179#[cfg(feature = "mysql_backend")]
180impl Queryable<Text, Mysql> for *const str {
181 type Row = Self;
182
183 fn build(row: Self::Row) -> deserialize::Result<Self> {
184 Ok(row)
185 }
186}
187
188#[cfg(feature = "mysql_backend")]
194impl FromSql<Binary, Mysql> for *const [u8] {
195 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
196 Ok(value.as_bytes() as *const [u8])
197 }
198}
199
200#[cfg(feature = "mysql_backend")]
201impl<'a> FromSqlRef<'a, Binary, Mysql> for &'a [u8] {
202 fn from_sql(bytes: MysqlValue<'a>) -> deserialize::Result<Self> {
203 Ok(bytes.as_bytes())
204 }
205}
206
207#[cfg(feature = "mysql_backend")]
208impl Queryable<Binary, Mysql> for *const [u8] {
209 type Row = Self;
210
211 fn build(row: Self::Row) -> deserialize::Result<Self> {
212 Ok(row)
213 }
214}