diesel/mysql_like/types/
primitives.rs1use crate::Queryable;
2use crate::deserialize::FromSqlRef;
3use crate::deserialize::{self, FromSql};
4use crate::mysql_like::MysqlLikeBackend;
5use crate::mysql_like::{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
49impl<DB: MysqlLikeBackend> FromSql<SmallInt, DB> for i16 {
50 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
51 match value.numeric_value()? {
52 NumericRepresentation::Tiny(x) => Ok(x.into()),
53 NumericRepresentation::Small(x) => Ok(x),
54 NumericRepresentation::Medium(x) => x.try_into().map_err(|_| {
55 Box::new(DeserializationError(
56 "Numeric overflow/underflow occurred".into(),
57 )) as _
58 }),
59 NumericRepresentation::Big(x) => x.try_into().map_err(|_| {
60 Box::new(DeserializationError(
61 "Numeric overflow/underflow occurred".into(),
62 )) as _
63 }),
64 NumericRepresentation::Float(x) => f32_to_i64(x)?.try_into().map_err(|_| {
65 Box::new(DeserializationError(
66 "Numeric overflow/underflow occurred".into(),
67 )) as _
68 }),
69 NumericRepresentation::Double(x) => f64_to_i64(x)?.try_into().map_err(|_| {
70 Box::new(DeserializationError(
71 "Numeric overflow/underflow occurred".into(),
72 )) as _
73 }),
74 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
75 }
76 }
77}
78
79impl<DB: MysqlLikeBackend> FromSql<Integer, DB> for i32 {
80 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
81 match value.numeric_value()? {
82 NumericRepresentation::Tiny(x) => Ok(x.into()),
83 NumericRepresentation::Small(x) => Ok(x.into()),
84 NumericRepresentation::Medium(x) => Ok(x),
85 NumericRepresentation::Big(x) => x.try_into().map_err(|_| {
86 Box::new(DeserializationError(
87 "Numeric overflow/underflow occurred".into(),
88 )) as _
89 }),
90 NumericRepresentation::Float(x) => f32_to_i64(x).and_then(|i| {
91 i.try_into().map_err(|_| {
92 Box::new(DeserializationError(
93 "Numeric overflow/underflow occurred".into(),
94 )) as _
95 })
96 }),
97 NumericRepresentation::Double(x) => f64_to_i64(x).and_then(|i| {
98 i.try_into().map_err(|_| {
99 Box::new(DeserializationError(
100 "Numeric overflow/underflow occurred".into(),
101 )) as _
102 })
103 }),
104 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
105 }
106 }
107}
108
109impl<DB: MysqlLikeBackend> FromSql<BigInt, DB> for i64 {
110 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
111 match value.numeric_value()? {
112 NumericRepresentation::Tiny(x) => Ok(x.into()),
113 NumericRepresentation::Small(x) => Ok(x.into()),
114 NumericRepresentation::Medium(x) => Ok(x.into()),
115 NumericRepresentation::Big(x) => Ok(x),
116 NumericRepresentation::Float(x) => f32_to_i64(x),
117 NumericRepresentation::Double(x) => f64_to_i64(x),
118 NumericRepresentation::Decimal(bytes) => decimal_to_integer(bytes),
119 }
120 }
121}
122
123impl<DB: MysqlLikeBackend> FromSql<Float, DB> for f32 {
124 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
125 match value.numeric_value()? {
126 NumericRepresentation::Tiny(x) => Ok(x.into()),
127 NumericRepresentation::Small(x) => Ok(x.into()),
128 NumericRepresentation::Medium(x) => Ok(x as Self),
129 NumericRepresentation::Big(x) => Ok(x as Self),
130 NumericRepresentation::Float(x) => Ok(x),
131 #[allow(clippy::cast_possible_truncation)]
133 NumericRepresentation::Double(x) => Ok(x as Self),
134 NumericRepresentation::Decimal(bytes) => Ok(str::from_utf8(bytes)?.parse()?),
135 }
136 }
137}
138
139impl<DB: MysqlLikeBackend> FromSql<Double, DB> for f64 {
140 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
141 match value.numeric_value()? {
142 NumericRepresentation::Tiny(x) => Ok(x.into()),
143 NumericRepresentation::Small(x) => Ok(x.into()),
144 NumericRepresentation::Medium(x) => Ok(x.into()),
145 NumericRepresentation::Big(x) => Ok(x as Self),
146 NumericRepresentation::Float(x) => Ok(x.into()),
147 NumericRepresentation::Double(x) => Ok(x),
148 NumericRepresentation::Decimal(bytes) => Ok(str::from_utf8(bytes)?.parse()?),
149 }
150 }
151}
152
153impl<DB: MysqlLikeBackend> FromSql<Text, DB> for *const str {
159 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
160 let string = str::from_utf8(value.as_bytes())?;
161 Ok(string as *const str)
162 }
163}
164
165impl<'a, DB: MysqlLikeBackend> FromSqlRef<'a, Text, DB> for &'a str {
166 fn from_sql(bytes: &'a mut MysqlValue<'_>) -> deserialize::Result<Self> {
167 let string = str::from_utf8(bytes.as_bytes())?;
168 Ok(string)
169 }
170}
171
172impl<DB: MysqlLikeBackend> Queryable<Text, DB> for *const str {
173 type Row = Self;
174
175 fn build(row: Self::Row) -> deserialize::Result<Self> {
176 Ok(row)
177 }
178}
179
180impl<DB: MysqlLikeBackend> FromSql<Binary, DB> for *const [u8] {
186 fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
187 Ok(value.as_bytes() as *const [u8])
188 }
189}
190
191impl<'a, DB: MysqlLikeBackend> FromSqlRef<'a, Binary, DB> for &'a [u8] {
192 fn from_sql(bytes: &'a mut MysqlValue<'_>) -> deserialize::Result<Self> {
193 Ok(bytes.as_bytes())
194 }
195}
196
197impl<DB: MysqlLikeBackend> Queryable<Binary, DB> for *const [u8] {
198 type Row = Self;
199
200 fn build(row: Self::Row) -> deserialize::Result<Self> {
201 Ok(row)
202 }
203}