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