1use super::{ffi, sqlite3_match_version, types::*};
2pub use blob::*;
3pub use passed_ref::*;
4use std::{marker::PhantomData, ptr, slice, str};
5pub use unsafe_ptr::*;
6pub use value_list::*;
7
8mod blob;
9mod passed_ref;
10mod test;
11mod unsafe_ptr;
12mod value_list;
13
14#[derive(Debug, Eq, PartialEq, Copy, Clone)]
15pub enum ValueType {
16 Integer,
17 Float,
18 Text,
19 Blob,
20 Null,
21}
22
23impl ValueType {
24 pub(crate) fn from_sqlite(val: i32) -> ValueType {
25 match val {
26 ffi::SQLITE_INTEGER => ValueType::Integer,
27 ffi::SQLITE_FLOAT => ValueType::Float,
28 ffi::SQLITE_TEXT => ValueType::Text,
29 ffi::SQLITE_BLOB => ValueType::Blob,
30 ffi::SQLITE_NULL => ValueType::Null,
31 _ => unreachable!(),
32 }
33 }
34}
35
36pub trait FromValue {
42 fn value_type(&self) -> ValueType;
46
47 fn is_null(&self) -> bool {
49 self.value_type() == ValueType::Null
50 }
51
52 fn get_i32(&self) -> i32;
54
55 fn get_i64(&self) -> i64;
57
58 fn get_f64(&self) -> f64;
60
61 unsafe fn get_blob_unchecked(&self) -> &[u8];
67
68 fn get_blob(&mut self) -> Result<&[u8]>;
70
71 fn try_get_blob(&self) -> Result<&[u8]> {
74 match self.value_type() {
75 ValueType::Blob => Ok(unsafe { self.get_blob_unchecked() }),
76 _ => Err(SQLITE_MISMATCH),
77 }
78 }
79
80 unsafe fn get_str_unchecked(&self) -> Result<&str> {
88 Ok(str::from_utf8(self.get_blob_unchecked())?)
89 }
90
91 fn get_str(&mut self) -> Result<&str> {
96 Ok(str::from_utf8(self.get_blob()?)?)
97 }
98
99 fn try_get_str(&self) -> Result<&str> {
103 match self.value_type() {
104 ValueType::Text => unsafe { self.get_str_unchecked() },
105 _ => Err(SQLITE_MISMATCH),
106 }
107 }
108
109 fn to_owned(&self) -> Result<Value> {
111 match self.value_type() {
112 ValueType::Integer => Ok(Value::from(self.get_i64())),
113 ValueType::Float => Ok(Value::from(self.get_f64())),
114 ValueType::Text => unsafe { Ok(Value::from(self.get_str_unchecked()?.to_owned())) },
115 ValueType::Blob => unsafe { Ok(Value::from(Blob::from(self.get_blob_unchecked()))) },
116 ValueType::Null => Ok(Value::Null),
117 }
118 }
119}
120
121#[repr(transparent)]
131pub struct ValueRef {
132 base: ffi::sqlite3_value,
133 phantom: PhantomData<*const ffi::sqlite3_value>,
135}
136
137impl ValueRef {
138 #[cfg_attr(not(modern_sqlite), allow(unused))]
139 pub(crate) unsafe fn from_ptr<'a>(p: *mut ffi::sqlite3_value) -> &'a mut ValueRef {
140 &mut *(p as *mut ValueRef)
141 }
142
143 pub unsafe fn as_ptr(&self) -> *mut ffi::sqlite3_value {
151 &self.base as *const ffi::sqlite3_value as _
152 }
153
154 pub fn numeric_type(&mut self) -> ValueType {
158 unsafe { ValueType::from_sqlite(ffi::sqlite3_value_numeric_type(self.as_ptr())) }
159 }
160
161 pub fn is_from_bind(&self) -> bool {
167 sqlite3_match_version! {
168 3_028_000 => unsafe { ffi::sqlite3_value_frombind(self.as_ptr()) != 0 },
169 _ => false,
170 }
171 }
172
173 pub fn nochange(&self) -> bool {
187 sqlite3_match_version! {
188 3_022_000 => (unsafe { ffi::sqlite3_value_nochange(self.as_ptr()) } != 0),
189 _ => false,
190 }
191 }
192
193 unsafe fn get_ref_internal<T: 'static>(&self) -> Option<&mut PassedRef<T>> {
195 sqlite3_match_version! {
196 3_020_000 => (ffi::sqlite3_value_pointer(self.as_ptr(), POINTER_TAG) as *mut PassedRef<T>).as_mut(),
197 _ => None,
198 }
199 }
200
201 pub fn get_ref<T: 'static>(&self) -> Option<&T> {
210 unsafe { self.get_ref_internal::<T>() }
211 .map(|x| PassedRef::get(x))
212 .unwrap_or(None)
213 }
214}
215
216impl FromValue for ValueRef {
217 fn value_type(&self) -> ValueType {
218 unsafe { ValueType::from_sqlite(ffi::sqlite3_value_type(self.as_ptr())) }
219 }
220
221 fn get_i32(&self) -> i32 {
222 unsafe { ffi::sqlite3_value_int(self.as_ptr()) }
223 }
224
225 fn get_i64(&self) -> i64 {
226 unsafe { ffi::sqlite3_value_int64(self.as_ptr()) }
227 }
228
229 fn get_f64(&self) -> f64 {
230 unsafe { ffi::sqlite3_value_double(self.as_ptr()) }
231 }
232
233 unsafe fn get_blob_unchecked(&self) -> &[u8] {
234 let len = ffi::sqlite3_value_bytes(self.as_ptr());
235 if len == 0 {
236 return &[];
237 }
238 let data = ffi::sqlite3_value_blob(self.as_ptr());
239 slice::from_raw_parts(data as _, len as _)
240 }
241
242 fn get_blob(&mut self) -> Result<&[u8]> {
243 unsafe {
244 let len = ffi::sqlite3_value_bytes(self.as_ptr());
245 if len == 0 {
246 return Ok(&[]);
247 }
248 let data = ffi::sqlite3_value_blob(self.as_ptr());
249 if data.is_null() {
250 return Err(SQLITE_NOMEM);
251 } else {
252 Ok(slice::from_raw_parts(data as _, len as _))
253 }
254 }
255 }
256}
257
258impl PartialEq for ValueRef {
259 fn eq(&self, other: &Self) -> bool {
262 if self.value_type() != other.value_type() {
263 return false;
264 }
265 match self.value_type() {
266 ValueType::Integer => self.get_i64() == other.get_i64(),
267 ValueType::Float => self.get_f64() == other.get_f64(),
268 ValueType::Text | ValueType::Blob => unsafe {
269 self.get_blob_unchecked() == other.get_blob_unchecked()
270 },
271 ValueType::Null => false,
272 }
273 }
274}
275
276impl std::fmt::Debug for ValueRef {
277 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
278 match self.value_type() {
279 ValueType::Integer => f.debug_tuple("Integer").field(&self.get_i64()).finish(),
280 ValueType::Float => f.debug_tuple("Float").field(&self.get_f64()).finish(),
281 ValueType::Text => f
282 .debug_tuple("Text")
283 .field(unsafe { &self.get_str_unchecked() })
284 .finish(),
285 ValueType::Blob => f
286 .debug_tuple("Blob")
287 .field(unsafe { &self.get_blob_unchecked() })
288 .finish(),
289 ValueType::Null => {
290 if let Some(r) = unsafe { self.get_ref_internal::<()>() } {
291 f.debug_tuple("Null").field(&r).finish()
292 } else {
293 f.debug_tuple("Null").finish()
294 }
295 }
296 }
297 }
298}
299
300#[derive(Debug, PartialEq, Clone)]
302pub enum Value {
303 Integer(i64),
304 Float(f64),
305 Text(String),
306 Blob(Blob),
307 Null,
308}
309
310macro_rules! value_from {
311 ($ty:ty as ($x:ident) => $impl:expr) => {
312 impl From<$ty> for Value {
313 fn from($x: $ty) -> Value {
314 $impl
315 }
316 }
317 };
318}
319
320value_from!(i32 as (x) => Value::Integer(x as _));
321value_from!(i64 as (x) => Value::Integer(x));
322value_from!(f64 as (x) => Value::Float(x));
323value_from!(String as (x) => Value::Text(x));
324value_from!(Blob as (x) => Value::Blob(x));
325value_from!(() as (_x) => Value::Null);