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