1use core::fmt::Display;
2use core::marker::PhantomData;
3
4use crate::backend::Backend;
5use crate::deserialize::{FromSql, FromSqlRef};
6use crate::query_builder::bind_collector::RawBytesBindCollector;
7use crate::serialize::ToSql;
8use crate::sql_types::EnumSqlType;
9
10#[derive(#[automatically_derived]
impl ::core::fmt::Debug for EnumVariant {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "EnumVariant",
"discriminant", &self.discriminant, "rust_name", &self.rust_name,
"sql_name", &&self.sql_name)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for EnumVariant {
#[inline]
fn clone(&self) -> EnumVariant {
let _: ::core::clone::AssertParamIsClone<i128>;
let _: ::core::clone::AssertParamIsClone<&'static str>;
let _: ::core::clone::AssertParamIsClone<&'static str>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for EnumVariant { }Copy)]
12pub struct EnumVariant {
13 pub discriminant: i128,
15 pub rust_name: &'static str,
17 pub sql_name: &'static str,
19}
20
21#[diagnostic::on_unimplemented(
26 message = "`{Self}` is no valid strategy to map an enum for backend `{DB}`",
27 note = "the `Sqlite` backend only support mapping to `Text` and `Integer` fields"
28)]
29pub trait EnumMapping<DB: Backend> {
30 fn map_to_database_value<'b>(
32 output: &mut crate::serialize::Output<'b, '_, DB>,
33 variant: &'static EnumVariant,
34 ) -> crate::serialize::Result;
35
36 fn map_from_database_value(
40 raw: DB::RawValue<'_>,
41 type_name: &'static str,
42 variants: &'static [EnumVariant],
43 ) -> crate::deserialize::Result<usize>;
44}
45
46#[derive(#[automatically_derived]
impl ::core::clone::Clone for StringMapping {
#[inline]
fn clone(&self) -> StringMapping { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for StringMapping { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for StringMapping {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "StringMapping")
}
}Debug)]
48pub struct StringMapping;
49
50#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug, ST: ::core::fmt::Debug> ::core::fmt::Debug for
IntMapping<T, ST> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "IntMapping",
&&self.0)
}
}Debug)]
58pub struct IntMapping<T, ST>(PhantomData<(T, ST)>);
59
60#[derive(#[automatically_derived]
impl ::core::clone::Clone for EnumTypeMapping {
#[inline]
fn clone(&self) -> EnumTypeMapping { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for EnumTypeMapping { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for EnumTypeMapping {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "EnumTypeMapping")
}
}Debug)]
62pub struct EnumTypeMapping;
63
64impl<const ANYWAY: bool, DB> EnumSqlType<ANYWAY, DB> for crate::sql_types::Text
65where
66 DB: Backend,
67 StringMapping: EnumMapping<DB>,
68{
69 type Strategy = crate::types::enum_::StringMapping;
70}
71
72impl<DB> EnumSqlType<true, DB> for crate::sql_types::Integer
73where
74 DB: Backend,
75 crate::types::enum_::IntMapping<i32, Self>: crate::types::enum_::EnumMapping<DB>,
76{
77 type Strategy = crate::types::enum_::IntMapping<i32, Self>;
78}
79
80impl<DB> EnumSqlType<true, DB> for crate::sql_types::BigInt
81where
82 DB: Backend,
83 crate::types::enum_::IntMapping<i64, Self>: crate::types::enum_::EnumMapping<DB>,
84{
85 type Strategy = crate::types::enum_::IntMapping<i64, Self>;
86}
87
88impl<DB> EnumSqlType<true, DB> for crate::sql_types::SmallInt
89where
90 DB: Backend,
91 crate::types::enum_::IntMapping<i16, Self>: crate::types::enum_::EnumMapping<DB>,
92{
93 type Strategy = crate::types::enum_::IntMapping<i16, Self>;
94}
95
96impl<DB> EnumSqlType<true, DB> for crate::sql_types::TinyInt
97where
98 DB: Backend,
99 IntMapping<i8, Self>: crate::types::enum_::EnumMapping<DB>,
100{
101 type Strategy = crate::types::enum_::IntMapping<i8, Self>;
102}
103
104impl<DB> EnumMapping<DB> for StringMapping
105where
106 DB: Backend,
107 for<'a> &'a str: FromSqlRef<'a, crate::sql_types::Text, DB>,
108 &'static str: ToSql<crate::sql_types::Text, DB>,
109{
110 fn map_to_database_value<'b>(
111 output: &mut crate::serialize::Output<'b, '_, DB>,
112 variant: &'static EnumVariant,
113 ) -> crate::serialize::Result {
114 <&str as crate::serialize::ToSql<crate::sql_types::Text, DB>>::to_sql(
115 &variant.sql_name,
116 output,
117 )
118 }
119
120 fn map_from_database_value(
121 mut raw: <DB as crate::backend::Backend>::RawValue<'_>,
122 type_name: &'static str,
123 variants: &'static [EnumVariant],
124 ) -> crate::deserialize::Result<usize> {
125 let s = <&str as FromSqlRef<crate::sql_types::Text, DB>>::from_sql(&mut raw)?;
126 Self::from_variant_name(type_name, variants, s)
127 }
128}
129
130impl StringMapping {
131 #[doc(hidden)]
132 pub fn from_variant_name(
133 type_name: &'static str,
134 variants: &'static [EnumVariant],
135 s: &str,
136 ) -> crate::deserialize::Result<usize> {
137 variants
138 .iter()
139 .position(|v| v.sql_name == s)
140 .ok_or_else(|| {
141 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Invalid enum variant `{1}` for `{2}`. Allowed variants are {0}",
variants.iter().map(|v|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", v.sql_name))
})).collect::<alloc::vec::Vec<_>>().join(", "), s,
type_name))
})alloc::format!(
142 "Invalid enum variant `{s}` for `{type_name}`. Allowed variants are {}",
143 variants
144 .iter()
145 .map(|v| alloc::format!("`{}`", v.sql_name))
146 .collect::<alloc::vec::Vec<_>>()
147 .join(", ")
148 )
149 .into()
150 })
151 }
152}
153
154impl<T, ST, DB> EnumMapping<DB> for IntMapping<T, ST>
155where
156 for<'a> DB: Backend<BindCollector<'a> = RawBytesBindCollector<DB>>,
157 T: ToSql<ST, DB> + FromSql<ST, DB>,
158 i128: TryInto<T, Error: Display> + TryFrom<T, Error: Display>,
159{
160 fn map_to_database_value<'b>(
161 output: &mut crate::serialize::Output<'b, '_, DB>,
162 variant: &'static EnumVariant,
163 ) -> crate::serialize::Result {
164 let v = variant.discriminant.try_into().map_err(|e| {
165 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Failed to convert discriminate to {0}: {1}",
core::any::type_name::<T>(), e))
})alloc::format!(
166 "Failed to convert discriminate to {}: {e}",
167 core::any::type_name::<T>()
168 )
169 })?;
170 <T as ToSql<ST, DB>>::to_sql(&v, &mut output.reborrow())
171 }
172
173 fn map_from_database_value(
174 raw: <DB as crate::backend::Backend>::RawValue<'_>,
175 type_name: &'static str,
176 variants: &'static [EnumVariant],
177 ) -> crate::deserialize::Result<usize> {
178 let i = <T as FromSql<ST, DB>>::from_sql(raw)?;
179 Self::from_discriminant(type_name, variants, i)
180 }
181}
182
183impl<T, ST> IntMapping<T, ST>
184where
185 i128: TryFrom<T, Error: Display>,
186{
187 #[doc(hidden)]
188 pub fn from_discriminant(
189 type_name: &'static str,
190 variants: &'static [EnumVariant],
191 value: T,
192 ) -> crate::deserialize::Result<usize> {
193 let i: i128 = value.try_into().map_err(|e| {
194 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Failed to convert {0} to discriminate: {1}",
core::any::type_name::<T>(), e))
})alloc::format!(
195 "Failed to convert {} to discriminate: {e}",
196 core::any::type_name::<T>()
197 )
198 })?;
199 variants
200 .iter()
201 .position(|v| v.discriminant == i)
202 .ok_or_else(|| {
203 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Invalid enum variant `{1}` for `{2}`. Allowed variants are {0}",
variants.iter().map(|v|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", v.discriminant))
})).collect::<alloc::vec::Vec<_>>().join(", "), i,
type_name))
})alloc::format!(
204 "Invalid enum variant `{i}` for `{type_name}`. Allowed variants are {}",
205 variants
206 .iter()
207 .map(|v| alloc::format!("`{}`", v.discriminant))
208 .collect::<alloc::vec::Vec<_>>()
209 .join(", ")
210 )
211 .into()
212 })
213 }
214}
215
216#[doc(hidden)]
217#[allow(unsafe_code)]
221pub unsafe trait IntegerMappingHelper
222where
223 Self: TryFrom<i128, Error: Display>,
224{
225 fn as_ref(v: &i128) -> Result<&Self, alloc::boxed::Box<dyn core::error::Error + Send + Sync>> {
226 let _: Self = (*v).try_into().map_err(|e| {
227 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Failed to convert discriminate to {0}: {1}",
core::any::type_name::<Self>(), e))
})alloc::format!(
228 "Failed to convert discriminate to {}: {e}",
229 core::any::type_name::<Self>()
230 )
231 })?;
232 let v = core::slice::from_ref(v);
233
234 let (front, v, tail) = unsafe {
235 v.align_to::<Self>()
239 };
240 if true {
if !front.is_empty() {
::core::panicking::panic("assertion failed: front.is_empty()")
};
};debug_assert!(front.is_empty());
241 if true {
if !tail.is_empty() {
::core::panicking::panic("assertion failed: tail.is_empty()")
};
};debug_assert!(tail.is_empty());
242
243 if falsecfg!(target_endian = "big") {
244 Ok(v.last().expect("We get at least one slice element"))
245 } else {
246 Ok(v.first().expect("We get at least one slice element"))
247 }
248 }
249}
250
251#[allow(unsafe_code)]
255unsafe impl IntegerMappingHelper for i64 {}
256#[allow(unsafe_code)]
257unsafe impl IntegerMappingHelper for i32 {}
258#[allow(unsafe_code)]
259unsafe impl IntegerMappingHelper for i16 {}
260#[allow(unsafe_code)]
261unsafe impl IntegerMappingHelper for i8 {}
262
263#[cfg(test)]
264mod tests {
265 use super::IntegerMappingHelper;
266
267 #[test]
268 fn check_as_ref_i64() {
269 assert_eq!(i64::as_ref(&1).unwrap(), &1);
270 assert_eq!(i64::as_ref(&42).unwrap(), &42);
271 assert_eq!(i64::as_ref(&0).unwrap(), &0);
272 assert_eq!(i64::as_ref(&(i64::MAX as i128)).unwrap(), &i64::MAX);
273 assert_eq!(i64::as_ref(&(i64::MIN as i128)).unwrap(), &i64::MIN);
274 assert!(i64::as_ref(&i128::MAX).is_err());
275 assert!(i64::as_ref(&i128::MIN).is_err());
276 assert!(i64::as_ref(&(i64::MAX as i128 + 1)).is_err());
277 assert!(i64::as_ref(&(i64::MIN as i128 - 1)).is_err());
278 }
279
280 #[test]
281 fn check_as_ref_i32() {
282 assert_eq!(i32::as_ref(&1).unwrap(), &1);
283 assert_eq!(i32::as_ref(&42).unwrap(), &42);
284 assert_eq!(i32::as_ref(&0).unwrap(), &0);
285 assert_eq!(i32::as_ref(&(i32::MAX as i128)).unwrap(), &i32::MAX);
286 assert_eq!(i32::as_ref(&(i32::MIN as i128)).unwrap(), &i32::MIN);
287 assert!(i32::as_ref(&i128::MAX).is_err());
288 assert!(i32::as_ref(&i128::MIN).is_err());
289 assert!(i32::as_ref(&(i64::MAX as i128)).is_err());
290 assert!(i32::as_ref(&(i64::MIN as i128)).is_err());
291 assert!(i32::as_ref(&(i32::MAX as i128 + 1)).is_err());
292 assert!(i32::as_ref(&(i32::MIN as i128 - 1)).is_err());
293 }
294
295 #[test]
296 fn check_as_ref_i16() {
297 assert_eq!(i16::as_ref(&1).unwrap(), &1);
298 assert_eq!(i16::as_ref(&42).unwrap(), &42);
299 assert_eq!(i16::as_ref(&0).unwrap(), &0);
300 assert_eq!(i16::as_ref(&(i16::MAX as i128)).unwrap(), &i16::MAX);
301 assert_eq!(i16::as_ref(&(i16::MIN as i128)).unwrap(), &i16::MIN);
302 assert!(i16::as_ref(&i128::MAX).is_err());
303 assert!(i16::as_ref(&i128::MIN).is_err());
304 assert!(i16::as_ref(&(i32::MAX as i128)).is_err());
305 assert!(i16::as_ref(&(i32::MIN as i128)).is_err());
306 assert!(i16::as_ref(&(i16::MAX as i128 + 1)).is_err());
307 assert!(i16::as_ref(&(i16::MIN as i128 - 1)).is_err());
308 }
309
310 #[test]
311 fn check_as_ref_i8() {
312 assert_eq!(i8::as_ref(&1).unwrap(), &1);
313 assert_eq!(i8::as_ref(&42).unwrap(), &42);
314 assert_eq!(i8::as_ref(&0).unwrap(), &0);
315 assert_eq!(i8::as_ref(&(i8::MAX as i128)).unwrap(), &i8::MAX);
316 assert_eq!(i8::as_ref(&(i8::MIN as i128)).unwrap(), &i8::MIN);
317 assert!(i8::as_ref(&i128::MAX).is_err());
318 assert!(i8::as_ref(&i128::MIN).is_err());
319 assert!(i8::as_ref(&(i16::MAX as i128)).is_err());
320 assert!(i8::as_ref(&(i16::MIN as i128)).is_err());
321 assert!(i8::as_ref(&(i8::MAX as i128 + 1)).is_err());
322 assert!(i8::as_ref(&(i8::MIN as i128 - 1)).is_err());
323 }
324}