sqlx_core/
encode.rs

1//! Provides [`Encode`] for encoding values for the database.
2
3use std::mem;
4
5use crate::database::Database;
6use crate::error::BoxDynError;
7
8/// The return type of [Encode::encode].
9#[must_use]
10pub enum IsNull {
11    /// The value is null; no data was written.
12    Yes,
13
14    /// The value is not null.
15    ///
16    /// This does not mean that data was written.
17    No,
18}
19
20impl IsNull {
21    pub fn is_null(&self) -> bool {
22        matches!(self, IsNull::Yes)
23    }
24}
25
26/// Encode a single value to be sent to the database.
27pub trait Encode<'q, DB: Database> {
28    /// Writes the value of `self` into `buf` in the expected format for the database.
29    fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer<'q>) -> Result<IsNull, BoxDynError>
30    where
31        Self: Sized,
32    {
33        self.encode_by_ref(buf)
34    }
35
36    /// Writes the value of `self` into `buf` without moving `self`.
37    ///
38    /// Where possible, make use of `encode` instead as it can take advantage of re-using
39    /// memory.
40    fn encode_by_ref(
41        &self,
42        buf: &mut <DB as Database>::ArgumentBuffer<'q>,
43    ) -> Result<IsNull, BoxDynError>;
44
45    fn produces(&self) -> Option<DB::TypeInfo> {
46        // `produces` is inherently a hook to allow database drivers to produce value-dependent
47        // type information; if the driver doesn't need this, it can leave this as `None`
48        None
49    }
50
51    #[inline]
52    fn size_hint(&self) -> usize {
53        mem::size_of_val(self)
54    }
55}
56
57impl<'q, T, DB: Database> Encode<'q, DB> for &'_ T
58where
59    T: Encode<'q, DB>,
60{
61    #[inline]
62    fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer<'q>) -> Result<IsNull, BoxDynError> {
63        <T as Encode<DB>>::encode_by_ref(self, buf)
64    }
65
66    #[inline]
67    fn encode_by_ref(
68        &self,
69        buf: &mut <DB as Database>::ArgumentBuffer<'q>,
70    ) -> Result<IsNull, BoxDynError> {
71        <&T as Encode<DB>>::encode(self, buf)
72    }
73
74    #[inline]
75    fn produces(&self) -> Option<DB::TypeInfo> {
76        (**self).produces()
77    }
78
79    #[inline]
80    fn size_hint(&self) -> usize {
81        (**self).size_hint()
82    }
83}
84
85#[macro_export]
86macro_rules! impl_encode_for_option {
87    ($DB:ident) => {
88        impl<'q, T> $crate::encode::Encode<'q, $DB> for Option<T>
89        where
90            T: $crate::encode::Encode<'q, $DB> + $crate::types::Type<$DB> + 'q,
91        {
92            #[inline]
93            fn produces(&self) -> Option<<$DB as $crate::database::Database>::TypeInfo> {
94                if let Some(v) = self {
95                    v.produces()
96                } else {
97                    T::type_info().into()
98                }
99            }
100
101            #[inline]
102            fn encode(
103                self,
104                buf: &mut <$DB as $crate::database::Database>::ArgumentBuffer<'q>,
105            ) -> Result<$crate::encode::IsNull, $crate::error::BoxDynError> {
106                if let Some(v) = self {
107                    v.encode(buf)
108                } else {
109                    Ok($crate::encode::IsNull::Yes)
110                }
111            }
112
113            #[inline]
114            fn encode_by_ref(
115                &self,
116                buf: &mut <$DB as $crate::database::Database>::ArgumentBuffer<'q>,
117            ) -> Result<$crate::encode::IsNull, $crate::error::BoxDynError> {
118                if let Some(v) = self {
119                    v.encode_by_ref(buf)
120                } else {
121                    Ok($crate::encode::IsNull::Yes)
122                }
123            }
124
125            #[inline]
126            fn size_hint(&self) -> usize {
127                self.as_ref().map_or(0, $crate::encode::Encode::size_hint)
128            }
129        }
130    };
131}