1use std::borrow::Cow;
4use std::mem;
5use std::rc::Rc;
6use std::sync::Arc;
7
8use crate::database::Database;
9use crate::error::BoxDynError;
10
11#[must_use]
13pub enum IsNull {
14 Yes,
16
17 No,
21}
22
23impl IsNull {
24 pub fn is_null(&self) -> bool {
25 matches!(self, IsNull::Yes)
26 }
27}
28
29pub trait Encode<'q, DB: Database> {
31 fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError>
33 where
34 Self: Sized,
35 {
36 self.encode_by_ref(buf)
37 }
38
39 fn encode_by_ref(
44 &self,
45 buf: &mut <DB as Database>::ArgumentBuffer,
46 ) -> Result<IsNull, BoxDynError>;
47
48 fn produces(&self) -> Option<DB::TypeInfo> {
49 None
52 }
53
54 #[inline]
55 fn size_hint(&self) -> usize {
56 mem::size_of_val(self)
57 }
58}
59
60impl<'q, T, DB: Database> Encode<'q, DB> for &'_ T
61where
62 T: Encode<'q, DB>,
63{
64 #[inline]
65 fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError> {
66 <T as Encode<DB>>::encode_by_ref(self, buf)
67 }
68
69 #[inline]
70 fn encode_by_ref(
71 &self,
72 buf: &mut <DB as Database>::ArgumentBuffer,
73 ) -> Result<IsNull, BoxDynError> {
74 <&T as Encode<DB>>::encode(self, buf)
75 }
76
77 #[inline]
78 fn produces(&self) -> Option<DB::TypeInfo> {
79 (**self).produces()
80 }
81
82 #[inline]
83 fn size_hint(&self) -> usize {
84 (**self).size_hint()
85 }
86}
87
88#[macro_export]
89macro_rules! impl_encode_for_option {
90 ($DB:ident) => {
91 impl<'q, T> $crate::encode::Encode<'q, $DB> for Option<T>
92 where
93 T: $crate::encode::Encode<'q, $DB> + $crate::types::Type<$DB> + 'q,
94 {
95 #[inline]
96 fn produces(&self) -> Option<<$DB as $crate::database::Database>::TypeInfo> {
97 if let Some(v) = self {
98 v.produces()
99 } else {
100 T::type_info().into()
101 }
102 }
103
104 #[inline]
105 fn encode(
106 self,
107 buf: &mut <$DB as $crate::database::Database>::ArgumentBuffer,
108 ) -> Result<$crate::encode::IsNull, $crate::error::BoxDynError> {
109 if let Some(v) = self {
110 v.encode(buf)
111 } else {
112 Ok($crate::encode::IsNull::Yes)
113 }
114 }
115
116 #[inline]
117 fn encode_by_ref(
118 &self,
119 buf: &mut <$DB as $crate::database::Database>::ArgumentBuffer,
120 ) -> Result<$crate::encode::IsNull, $crate::error::BoxDynError> {
121 if let Some(v) = self {
122 v.encode_by_ref(buf)
123 } else {
124 Ok($crate::encode::IsNull::Yes)
125 }
126 }
127
128 #[inline]
129 fn size_hint(&self) -> usize {
130 self.as_ref().map_or(0, $crate::encode::Encode::size_hint)
131 }
132 }
133 };
134}
135
136macro_rules! impl_encode_for_smartpointer {
137 ($smart_pointer:ty) => {
138 impl<'q, T, DB: Database> Encode<'q, DB> for $smart_pointer
139 where
140 T: Encode<'q, DB>,
141 {
142 #[inline]
143 fn encode(
144 self,
145 buf: &mut <DB as Database>::ArgumentBuffer,
146 ) -> Result<IsNull, BoxDynError> {
147 <T as Encode<DB>>::encode_by_ref(self.as_ref(), buf)
148 }
149
150 #[inline]
151 fn encode_by_ref(
152 &self,
153 buf: &mut <DB as Database>::ArgumentBuffer,
154 ) -> Result<IsNull, BoxDynError> {
155 <&T as Encode<DB>>::encode(self, buf)
156 }
157
158 #[inline]
159 fn produces(&self) -> Option<DB::TypeInfo> {
160 (**self).produces()
161 }
162
163 #[inline]
164 fn size_hint(&self) -> usize {
165 (**self).size_hint()
166 }
167 }
168 };
169}
170
171impl_encode_for_smartpointer!(Arc<T>);
172impl_encode_for_smartpointer!(Box<T>);
173impl_encode_for_smartpointer!(Rc<T>);
174
175impl<'q, T, DB: Database> Encode<'q, DB> for Cow<'q, T>
176where
177 T: Encode<'q, DB>,
178 T: ToOwned,
179{
180 #[inline]
181 fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError> {
182 <&T as Encode<DB>>::encode_by_ref(&self.as_ref(), buf)
183 }
184
185 #[inline]
186 fn encode_by_ref(
187 &self,
188 buf: &mut <DB as Database>::ArgumentBuffer,
189 ) -> Result<IsNull, BoxDynError> {
190 <&T as Encode<DB>>::encode_by_ref(&self.as_ref(), buf)
191 }
192
193 #[inline]
194 fn produces(&self) -> Option<DB::TypeInfo> {
195 <&T as Encode<DB>>::produces(&self.as_ref())
196 }
197
198 #[inline]
199 fn size_hint(&self) -> usize {
200 <&T as Encode<DB>>::size_hint(&self.as_ref())
201 }
202}
203
204#[macro_export]
205macro_rules! forward_encode_impl {
206 ($for_type:ty, $forward_to:ty, $db:ident) => {
207 impl<'q> Encode<'q, $db> for $for_type {
208 fn encode_by_ref(
209 &self,
210 buf: &mut <$db as sqlx_core::database::Database>::ArgumentBuffer,
211 ) -> Result<IsNull, BoxDynError> {
212 <$forward_to as Encode<$db>>::encode(self.as_ref(), buf)
213 }
214 }
215 };
216}