1use std::ffi::{c_double, c_int};
2
3use crate::{ColumnIndex, ParameterIndex, Result, Statement, Type, Value};
5
6macro_rules! transient(
8 () => (
9 std::mem::transmute::<
10 *const std::ffi::c_void,
11 std::option::Option<unsafe extern "C" fn(*mut std::ffi::c_void)>
12 >(!0 as *const core::ffi::c_void)
13 );
14);
15
16pub trait Bindable {
18 fn bind(self, _: &Statement) -> Result<()>;
20}
21
22pub trait BindableWithIndex {
24 fn bind<T: ParameterIndex>(self, _: &Statement, _: T) -> Result<()>;
28}
29
30pub trait ReadableWithIndex: Sized {
32 fn read<T: ColumnIndex>(_: &Statement, _: T) -> Result<Self>;
36}
37
38impl<T, U> Bindable for (T, U)
39where
40 T: ParameterIndex,
41 U: BindableWithIndex,
42{
43 #[inline]
44 fn bind(self, statement: &Statement) -> Result<()> {
45 self.1.bind(statement, self.0)
46 }
47}
48
49impl<T> Bindable for &[T]
50where
51 T: BindableWithIndex + Clone,
52{
53 fn bind(self, statement: &Statement) -> Result<()> {
54 for (index, value) in self.iter().enumerate() {
55 value.clone().bind(statement, index + 1)?;
56 }
57 Ok(())
58 }
59}
60
61impl<T, U> Bindable for &[(T, U)]
62where
63 T: ParameterIndex,
64 U: BindableWithIndex + Clone,
65{
66 fn bind(self, statement: &Statement) -> Result<()> {
67 for (index, value) in self.iter() {
68 value.clone().bind(statement, *index)?;
69 }
70 Ok(())
71 }
72}
73
74impl BindableWithIndex for &[u8] {
75 fn bind<T: ParameterIndex>(self, statement: &Statement, index: T) -> Result<()> {
76 unsafe {
77 ok!(
78 statement.raw.1,
79 ffi::sqlite3_bind_blob(
80 statement.raw.0,
81 index.index(statement)? as c_int,
82 self.as_ptr() as *const _,
83 self.len() as c_int,
84 transient!(),
85 )
86 );
87 }
88 Ok(())
89 }
90}
91
92impl BindableWithIndex for f64 {
93 fn bind<T: ParameterIndex>(self, statement: &Statement, index: T) -> Result<()> {
94 unsafe {
95 ok!(
96 statement.raw.1,
97 ffi::sqlite3_bind_double(
98 statement.raw.0,
99 index.index(statement)? as c_int,
100 self as c_double
101 )
102 );
103 }
104 Ok(())
105 }
106}
107
108impl BindableWithIndex for i64 {
109 fn bind<T: ParameterIndex>(self, statement: &Statement, index: T) -> Result<()> {
110 unsafe {
111 ok!(
112 statement.raw.1,
113 ffi::sqlite3_bind_int64(
114 statement.raw.0,
115 index.index(statement)? as c_int,
116 self as ffi::sqlite3_int64
117 )
118 );
119 }
120 Ok(())
121 }
122}
123
124impl BindableWithIndex for &str {
125 fn bind<T: ParameterIndex>(self, statement: &Statement, index: T) -> Result<()> {
126 unsafe {
127 ok!(
128 statement.raw.1,
129 ffi::sqlite3_bind_text(
130 statement.raw.0,
131 index.index(statement)? as c_int,
132 self.as_ptr() as *const _,
133 self.len() as c_int,
134 transient!(),
135 )
136 );
137 }
138 Ok(())
139 }
140}
141
142impl BindableWithIndex for () {
143 fn bind<T: ParameterIndex>(self, statement: &Statement, index: T) -> Result<()> {
144 unsafe {
145 ok!(
146 statement.raw.1,
147 ffi::sqlite3_bind_null(statement.raw.0, index.index(statement)? as c_int)
148 );
149 }
150 Ok(())
151 }
152}
153
154impl BindableWithIndex for Value {
155 #[inline]
156 fn bind<T: ParameterIndex>(self, statement: &Statement, index: T) -> Result<()> {
157 (index, &self).bind(statement)
158 }
159}
160
161impl BindableWithIndex for &Value {
162 fn bind<T: ParameterIndex>(self, statement: &Statement, index: T) -> Result<()> {
163 match self {
164 Value::Binary(ref value) => (value as &[u8]).bind(statement, index),
165 Value::Float(value) => value.bind(statement, index),
166 Value::Integer(value) => value.bind(statement, index),
167 Value::String(ref value) => (value as &str).bind(statement, index),
168 Value::Null => ().bind(statement, index),
169 }
170 }
171}
172
173impl<T> BindableWithIndex for Option<T>
174where
175 T: BindableWithIndex,
176{
177 #[inline]
178 fn bind<U: ParameterIndex>(self, statement: &Statement, index: U) -> Result<()> {
179 match self {
180 Some(value) => value.bind(statement, index),
181 None => ().bind(statement, index),
182 }
183 }
184}
185
186impl<T> BindableWithIndex for &Option<T>
187where
188 T: BindableWithIndex + Clone,
189{
190 #[inline]
191 fn bind<U: ParameterIndex>(self, statement: &Statement, index: U) -> Result<()> {
192 match self {
193 Some(value) => value.clone().bind(statement, index),
194 None => ().bind(statement, index),
195 }
196 }
197}
198
199impl ReadableWithIndex for Vec<u8> {
200 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
201 use std::ptr::copy_nonoverlapping as copy;
202 unsafe {
203 let pointer =
204 ffi::sqlite3_column_blob(statement.raw.0, index.index(statement)? as c_int);
205 if pointer.is_null() {
206 return Ok(vec![]);
207 }
208 let count = ffi::sqlite3_column_bytes(statement.raw.0, index.index(statement)? as c_int)
209 as usize;
210 let mut buffer = Vec::with_capacity(count);
211 copy(pointer as *const u8, buffer.as_mut_ptr(), count);
212 buffer.set_len(count);
213 Ok(buffer)
214 }
215 }
216}
217
218impl ReadableWithIndex for f64 {
219 #[allow(clippy::unnecessary_cast)]
220 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
221 Ok(unsafe {
222 ffi::sqlite3_column_double(statement.raw.0, index.index(statement)? as c_int) as f64
223 })
224 }
225}
226
227impl ReadableWithIndex for i64 {
228 #[allow(clippy::unnecessary_cast)]
229 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
230 Ok(unsafe {
231 ffi::sqlite3_column_int64(statement.raw.0, index.index(statement)? as c_int) as i64
232 })
233 }
234}
235
236impl ReadableWithIndex for String {
237 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
238 unsafe {
239 let pointer =
240 ffi::sqlite3_column_text(statement.raw.0, index.index(statement)? as c_int);
241 if pointer.is_null() {
242 raise!("cannot read a text column");
243 }
244 Ok(c_str_to_string!(pointer))
245 }
246 }
247}
248
249impl ReadableWithIndex for Value {
250 fn read<T: ColumnIndex>(statement: &Statement, index: T) -> Result<Self> {
251 Ok(match statement.column_type(index)? {
252 Type::Binary => Value::Binary(ReadableWithIndex::read(statement, index)?),
253 Type::Float => Value::Float(ReadableWithIndex::read(statement, index)?),
254 Type::Integer => Value::Integer(ReadableWithIndex::read(statement, index)?),
255 Type::String => Value::String(ReadableWithIndex::read(statement, index)?),
256 Type::Null => Value::Null,
257 })
258 }
259}
260
261impl<T: ReadableWithIndex> ReadableWithIndex for Option<T> {
262 fn read<U: ColumnIndex>(statement: &Statement, index: U) -> Result<Self> {
263 if statement.column_type(index)? == Type::Null {
264 Ok(None)
265 } else {
266 T::read(statement, index).map(Some)
267 }
268 }
269}