asqlite/convert/
into_sql.rs

1use super::SqlRef;
2use crate::{convert::Sql, ErrorKind, Result, ZeroBlob};
3use std::{rc::Rc, sync::Arc};
4
5/// Convert Rust types to SQLite parameters.
6///
7/// In cases where verifications may fail, an error can be returned.
8///
9/// # Default implementations
10///
11/// By default, the following implementations are provided:
12///
13/// | Rust type(s)                              | SQL type      | Infallible |
14/// |-------------------------------------------|---------------|------------|
15/// | `bool, i8, i16, i32, i64, u8, u16, u32`   | `INTEGER`     | Yes        |
16/// | `i128, isize, u64, u128, usize`           | `INTEGER`     | No         |
17/// | `f64, f32`                                | `REAL`        | Yes        |
18/// | `[u8], Vec<u8>`                           | `BLOB`        | Yes        |
19/// | [`ZeroBlob`]                              | `BLOB`        | Yes        |
20/// | `str, String`                             | `TEXT`        | Yes        |
21/// | [`()`](primitive@unit)                    | `NULL`        | Yes        |
22///
23/// Aditionally, [`Option<T>`] maps to either the SQL type of `T`, or `NULL`
24/// if the `Option` evaluates to `None`.
25///
26/// The implementations for `[u8]` and `str` automatically include
27/// `Arc<[u8]>`, `Box<[u8]>`, `Arc<str>` and `Box<str>`.
28pub trait IntoSql {
29    /// Converts into a SQL value.
30    fn into_sql(self) -> Result<Sql>;
31}
32
33macro_rules! impl_transparent {
34    ($($x: ty),*) => {
35        $(
36            impl<T> IntoSql for $x
37            where
38                for<'a> &'a T: IntoSql,
39            {
40                #[inline]
41                fn into_sql(self) -> Result<Sql> {
42                    (&*self).into_sql()
43                }
44            }
45        )*
46    };
47}
48
49impl_transparent!(&'_ mut T, Box<T>, Arc<T>, Rc<T>);
50
51impl<const N: usize> IntoSql for [u8; N] {
52    #[inline]
53    fn into_sql(self) -> Result<Sql> {
54        Ok(Sql::Blob(self.into()))
55    }
56}
57
58impl IntoSql for &[u8] {
59    #[inline]
60    fn into_sql(self) -> Result<Sql> {
61        Ok(Sql::Blob(self.into()))
62    }
63}
64
65impl IntoSql for Vec<u8> {
66    #[inline]
67    fn into_sql(self) -> Result<Sql> {
68        Ok(Sql::Blob(self))
69    }
70}
71
72impl IntoSql for &'_ Vec<u8> {
73    #[inline]
74    fn into_sql(self) -> Result<Sql> {
75        self.as_slice().into_sql()
76    }
77}
78
79impl IntoSql for &str {
80    #[inline]
81    fn into_sql(self) -> Result<Sql> {
82        Ok(Sql::Text(self.into()))
83    }
84}
85
86impl IntoSql for String {
87    #[inline]
88    fn into_sql(self) -> Result<Sql> {
89        Ok(Sql::Text(self))
90    }
91}
92
93impl IntoSql for &'_ String {
94    #[inline]
95    fn into_sql(self) -> Result<Sql> {
96        self.as_str().into_sql()
97    }
98}
99
100macro_rules! impl_int_lossless {
101    ($($x: ty),*) => {
102        $(
103            impl IntoSql for $x {
104                #[inline]
105                fn into_sql(self) -> Result<Sql> {
106                    Ok(Sql::Int(i64::from(self)))
107                }
108            }
109
110            impl IntoSql for &'_ $x {
111                #[inline]
112                fn into_sql(self) -> Result<Sql> {
113                    (*self).into_sql()
114                }
115            }
116        )*
117    };
118}
119
120impl_int_lossless!(bool, i8, i16, i32, i64, u8, u16, u32);
121
122macro_rules! impl_int {
123    ($($x: ty),*) => {
124        $(
125            impl IntoSql for $x {
126                #[inline]
127                fn into_sql(self) -> Result<Sql> {
128                    Ok(Sql::Int(i64::try_from(self).map_err(|_| {
129                        ErrorKind::DatatypeMismatch
130                    })?))
131                }
132            }
133
134            impl IntoSql for &'_ $x {
135                #[inline]
136                fn into_sql(self) -> Result<Sql> {
137                    (*self).into_sql()
138                }
139            }
140        )*
141    };
142}
143
144impl_int!(i128, isize, u64, u128, usize);
145
146impl IntoSql for f64 {
147    #[inline]
148    fn into_sql(self) -> Result<Sql> {
149        Ok(Sql::Float(self))
150    }
151}
152
153impl IntoSql for f32 {
154    #[inline]
155    fn into_sql(self) -> Result<Sql> {
156        Ok(Sql::Float(f64::from(self)))
157    }
158}
159
160impl IntoSql for &'_ f64 {
161    #[inline]
162    fn into_sql(self) -> Result<Sql> {
163        (*self).into_sql()
164    }
165}
166
167impl IntoSql for &'_ f32 {
168    #[inline]
169    fn into_sql(self) -> Result<Sql> {
170        (*self).into_sql()
171    }
172}
173
174impl<T> IntoSql for Option<T>
175where
176    T: IntoSql,
177{
178    #[inline]
179    fn into_sql(self) -> Result<Sql> {
180        match self {
181            Some(inner) => inner.into_sql(),
182            None => Ok(Sql::Null),
183        }
184    }
185}
186
187impl<'a, T> IntoSql for &'a Option<T>
188where
189    &'a T: IntoSql,
190{
191    #[inline]
192    fn into_sql(self) -> Result<Sql> {
193        match self {
194            Some(inner) => inner.into_sql(),
195            None => Ok(Sql::Null),
196        }
197    }
198}
199
200impl IntoSql for () {
201    #[inline]
202    fn into_sql(self) -> Result<Sql> {
203        Ok(Sql::Null)
204    }
205}
206
207impl IntoSql for &'_ () {
208    #[inline]
209    fn into_sql(self) -> Result<Sql> {
210        Ok(Sql::Null)
211    }
212}
213
214impl IntoSql for ZeroBlob {
215    #[inline]
216    fn into_sql(self) -> Result<Sql> {
217        Ok(Sql::ZeroBlob(self))
218    }
219}
220
221impl IntoSql for &'_ ZeroBlob {
222    #[inline]
223    fn into_sql(self) -> Result<Sql> {
224        (*self).into_sql()
225    }
226}
227
228impl IntoSql for Sql {
229    #[inline]
230    fn into_sql(self) -> Result<Sql> {
231        Ok(self)
232    }
233}
234
235impl IntoSql for SqlRef<'_> {
236    #[inline]
237    fn into_sql(self) -> Result<Sql> {
238        Ok(self.into())
239    }
240}
241
242impl IntoSql for &'_ Sql {
243    #[inline]
244    fn into_sql(self) -> Result<Sql> {
245        Ok(self.clone())
246    }
247}
248
249impl IntoSql for &'_ SqlRef<'_> {
250    #[inline]
251    fn into_sql(self) -> Result<Sql> {
252        Ok((*self).into())
253    }
254}