1use core::num::{
4 NonZeroI8,
5 NonZeroU8,
6 NonZeroI16,
7 NonZeroU16,
8 NonZeroI32,
9 NonZeroU32,
10 NonZeroI64,
11 NonZeroU64,
12 NonZeroIsize,
13 NonZeroUsize,
14};
15use core::str::FromStr;
16use core::fmt::{self, Display, Formatter, Write};
17use std::borrow::Cow;
18use std::rc::Rc;
19use std::sync::Arc;
20use std::collections::{HashMap, BTreeMap};
21use rusqlite::{Statement, ToSql, types::{Value, ValueRef, Null, ToSqlOutput}};
22#[cfg(feature = "not-nan")]
23use ordered_float::NotNan;
24#[cfg(feature = "chrono")]
25use chrono::{DateTime, Utc, FixedOffset, Local};
26#[cfg(feature = "uuid")]
27use uuid::Uuid;
28#[cfg(feature = "json")]
29use serde_json::Value as JsonValue;
30use crate::error::{Error, Result};
31
32
33#[repr(u8)]
40#[allow(missing_docs)]
41#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
42pub enum ParamPrefix {
43 #[default]
44 Dollar = b'$',
45 Colon = b':',
46 Question = b'?',
47 At = b'@',
48}
49
50impl ParamPrefix {
51 pub const fn as_byte(self) -> u8 {
53 self as u8
54 }
55
56 pub const fn as_char(self) -> char {
58 self as u8 as char
59 }
60}
61
62impl From<ParamPrefix> for u8 {
63 fn from(prefix: ParamPrefix) -> Self {
64 prefix.as_byte()
65 }
66}
67
68impl From<ParamPrefix> for char {
69 fn from(prefix: ParamPrefix) -> Self {
70 prefix.as_char()
71 }
72}
73
74impl TryFrom<char> for ParamPrefix {
75 type Error = Error;
76
77 fn try_from(ch: char) -> Result<Self, Self::Error> {
78 match ch {
79 '$' => Ok(ParamPrefix::Dollar),
80 ':' => Ok(ParamPrefix::Colon),
81 '?' => Ok(ParamPrefix::Question),
82 '@' => Ok(ParamPrefix::At),
83 _ => Err(Error::message(format_args!("invalid parameter prefix: `{ch}`"))),
84 }
85 }
86}
87
88impl TryFrom<u8> for ParamPrefix {
89 type Error = Error;
90
91 fn try_from(byte: u8) -> Result<Self, Self::Error> {
92 char::from(byte).try_into()
93 }
94}
95
96impl Display for ParamPrefix {
97 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
98 f.write_char(self.as_char())
99 }
100}
101
102impl FromStr for ParamPrefix {
103 type Err = Error;
104
105 fn from_str(s: &str) -> Result<Self, Self::Err> {
106 char::from_str(s).map_err(Error::other).and_then(Self::try_from)
107 }
108}
109
110pub trait Param {
123 const PREFIX: ParamPrefix;
125
126 fn bind(&self, statement: &mut Statement<'_>) -> Result<()>;
128}
129
130fn bind_primitive<T: ToSql>(statement: &mut Statement<'_>, value: T) -> Result<()> {
133 let expected = statement.parameter_count();
134 let actual = 1;
135
136 if actual == expected {
137 statement.raw_bind_parameter(1, value)?;
138 Ok(())
139 } else {
140 Err(Error::ParamCountMismatch { expected, actual })
141 }
142}
143
144macro_rules! impl_param_for_primitive {
145 ($($ty:ty,)*) => {$(
146 impl Param for $ty {
147 const PREFIX: ParamPrefix = ParamPrefix::Question;
149
150 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
151 bind_primitive(statement, self)
152 }
153 }
154 )*}
155}
156
157impl_param_for_primitive!{
158 bool,
159 i8,
160 u8,
161 i16,
162 u16,
163 i32,
164 u32,
165 i64,
166 u64,
167 isize,
168 usize,
169 NonZeroI8,
170 NonZeroU8,
171 NonZeroI16,
172 NonZeroU16,
173 NonZeroI32,
174 NonZeroU32,
175 NonZeroI64,
176 NonZeroU64,
177 NonZeroIsize,
178 NonZeroUsize,
179 f32,
180 f64,
181 str,
182 [u8],
183 String,
184 Vec<u8>,
185 Value,
186 ToSqlOutput<'_>,
187 Null,
188}
189
190#[cfg(feature = "not-nan")]
191impl Param for NotNan<f32> {
192 const PREFIX: ParamPrefix = ParamPrefix::Question;
194
195 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
196 bind_primitive(statement, self.into_inner())
197 }
198}
199
200#[cfg(feature = "not-nan")]
201impl Param for NotNan<f64> {
202 const PREFIX: ParamPrefix = ParamPrefix::Question;
204
205 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
206 bind_primitive(statement, self.into_inner())
207 }
208}
209
210#[cfg(feature = "chrono")]
211impl_param_for_primitive! {
212 DateTime<Utc>,
213 DateTime<FixedOffset>,
214 DateTime<Local>,
215}
216
217#[cfg(feature = "uuid")]
218impl_param_for_primitive!{
219 Uuid,
220}
221
222#[cfg(feature = "json")]
223impl_param_for_primitive!{
224 JsonValue,
225}
226
227impl Param for ValueRef<'_> {
228 const PREFIX: ParamPrefix = ParamPrefix::Question;
230
231 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
232 bind_primitive(statement, ToSqlOutput::Borrowed(*self))
233 }
234}
235
236impl<const N: usize> Param for [u8; N] {
237 const PREFIX: ParamPrefix = ParamPrefix::Question;
239
240 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
241 bind_primitive(statement, self)
242 }
243}
244
245macro_rules! impl_param_for_tuple {
246 () => {
247 impl Param for () {
248 const PREFIX: ParamPrefix = ParamPrefix::Question;
250
251 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
252 let expected = statement.parameter_count();
253 let actual = 0;
254
255 if actual == expected {
256 Ok(())
257 } else {
258 Err(Error::ParamCountMismatch { expected, actual })
259 }
260 }
261 }
262 };
263 ($head_id:ident => $head_ty:ident; $($rest_id:ident => $rest_ty:ident;)*) => {
264 impl<$head_ty, $($rest_ty,)*> Param for ($head_ty, $($rest_ty,)*)
265 where
266 $head_ty: ToSql,
267 $($rest_ty: ToSql,)*
268 {
269 const PREFIX: ParamPrefix = ParamPrefix::Question;
271
272 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
273 let ($head_id, $($rest_id,)*) = self;
274
275 #[allow(unused_mut)]
276 let mut index = 1;
277 statement.raw_bind_parameter(index, $head_id)?;
278
279 $(
280 index += 1;
281 statement.raw_bind_parameter(index, $rest_id)?;
282 )*
283
284 let expected = statement.parameter_count();
285 let actual = index;
286
287 if actual == expected {
288 Ok(())
289 } else {
290 Err(Error::ParamCountMismatch { expected, actual })
291 }
292 }
293 }
294 impl_param_for_tuple!($($rest_id => $rest_ty;)*);
295 };
296}
297
298impl_param_for_tuple!{
299 a => A;
300 b => B;
301 c => C;
302 d => D;
303 e => E;
304 f => F;
305 g => G;
306 h => H;
307 i => I;
308 j => J;
309 k => K;
310 l => L;
311 m => M;
312 n => N;
313 o => O;
314 p => P;
315 q => Q;
316 r => R;
317 s => S;
318 t => T;
319 u => U;
320 v => V;
321 w => W;
322 x => X;
323 y => Y;
324 z => Z;
325}
326
327macro_rules! impl_param_for_wrapper {
328 ($($ty:ty;)*) => {$(
329 impl<T: ?Sized + Param> Param for $ty {
330 const PREFIX: ParamPrefix = T::PREFIX;
331
332 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
333 let body = |value: &$ty, statement| Param::bind(&**value, statement);
334 body(self, statement)
335 }
336 }
337 )*}
338}
339
340impl_param_for_wrapper! {
341 &T;
342 &mut T;
343 Box<T>;
344 Rc<T>;
345 Arc<T>;
346}
347
348impl<T> Param for Cow<'_, T>
349where
350 T: ?Sized + ToOwned + Param,
351{
352 const PREFIX: ParamPrefix = T::PREFIX;
353
354 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
355 Param::bind(&**self, statement)
356 }
357}
358
359impl<T: ToSql> Param for Option<T> {
360 const PREFIX: ParamPrefix = ParamPrefix::Question;
362
363 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
364 bind_primitive(statement, self)
365 }
366}
367
368impl<K, V> Param for HashMap<K, V>
369where
370 K: Display,
371 V: ToSql,
372{
373 const PREFIX: ParamPrefix = ParamPrefix::Dollar;
375
376 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
377 let expected = statement.parameter_count();
378 let actual = self.len();
379
380 if actual != expected {
381 return Err(Error::ParamCountMismatch { expected, actual });
382 }
383
384 let mut name_buf = String::new();
386
387 for (key, value) in self {
388 name_buf.clear();
389 write!(name_buf, "{}{}", Self::PREFIX, key)?;
390
391 let index = statement.parameter_index(name_buf.as_str())?.ok_or_else(|| {
392 Error::unknown_param_dyn(&name_buf)
393 })?;
394
395 statement.raw_bind_parameter(index, value)?;
396 }
397
398 Ok(())
399 }
400}
401
402impl<K, V> Param for BTreeMap<K, V>
403where
404 K: Display,
405 V: ToSql,
406{
407 const PREFIX: ParamPrefix = ParamPrefix::Dollar;
409
410 fn bind(&self, statement: &mut Statement<'_>) -> Result<()> {
411 let expected = statement.parameter_count();
412 let actual = self.len();
413
414 if actual != expected {
415 return Err(Error::ParamCountMismatch { expected, actual });
416 }
417
418 let mut name_buf = String::new();
420
421 for (key, value) in self {
422 name_buf.clear();
423 write!(name_buf, "{}{}", Self::PREFIX, key)?;
424
425 let index = statement.parameter_index(name_buf.as_str())?.ok_or_else(|| {
426 Error::unknown_param_dyn(&name_buf)
427 })?;
428
429 statement.raw_bind_parameter(index, value)?;
430 }
431
432 Ok(())
433 }
434}