Skip to main content

rbdc_sqlite/
value.rs

1use std::ptr::NonNull;
2use std::slice::from_raw_parts;
3use std::str::from_utf8;
4use std::sync::Arc;
5
6use libsqlite3_sys::{
7    sqlite3_value, sqlite3_value_blob, sqlite3_value_bytes, sqlite3_value_double,
8    sqlite3_value_dup, sqlite3_value_free, sqlite3_value_int, sqlite3_value_int64,
9    sqlite3_value_type, SQLITE_NULL,
10};
11
12use crate::type_info::DataType;
13use crate::SqliteTypeInfo;
14use rbdc::error::Error;
15use std::borrow::Cow;
16
17enum SqliteValueData<'r> {
18    Value(&'r SqliteValue),
19}
20
21pub struct SqliteValueRef<'r>(SqliteValueData<'r>);
22
23impl<'r> SqliteValueRef<'r> {
24    pub(crate) fn value(value: &'r SqliteValue) -> Self {
25        Self(SqliteValueData::Value(value))
26    }
27
28    pub(super) fn int(&self) -> i32 {
29        match self.0 {
30            SqliteValueData::Value(v) => v.int(),
31        }
32    }
33
34    pub(super) fn int64(&self) -> i64 {
35        match self.0 {
36            SqliteValueData::Value(v) => v.int64(),
37        }
38    }
39
40    pub(super) fn double(&self) -> f64 {
41        match self.0 {
42            SqliteValueData::Value(v) => v.double(),
43        }
44    }
45
46    pub(super) fn blob(&self) -> &'r [u8] {
47        match self.0 {
48            SqliteValueData::Value(v) => v.blob(),
49        }
50    }
51
52    pub(super) fn text(&self) -> Result<&'r str, Error> {
53        match self.0 {
54            SqliteValueData::Value(v) => v.text(),
55        }
56    }
57}
58
59impl<'r> SqliteValueRef<'r> {
60    pub fn to_owned(&self) -> SqliteValue {
61        match self.0 {
62            SqliteValueData::Value(v) => v.clone(),
63        }
64    }
65
66    pub fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
67        match self.0 {
68            SqliteValueData::Value(v) => v.type_info(),
69        }
70    }
71
72    pub fn type_info_opt(&self) -> Option<SqliteTypeInfo> {
73        match self.0 {
74            SqliteValueData::Value(v) => v.type_info_opt(),
75        }
76    }
77
78    pub fn is_null(&self) -> bool {
79        match self.0 {
80            SqliteValueData::Value(v) => v.is_null(),
81        }
82    }
83}
84
85#[derive(Clone, Debug)]
86pub struct SqliteValue {
87    pub(crate) handle: Arc<ValueHandle>,
88    pub(crate) type_info: SqliteTypeInfo,
89}
90
91#[derive(Debug)]
92pub(crate) struct ValueHandle(NonNull<sqlite3_value>);
93
94// SAFE: only protected value objects are stored in SqliteValue
95unsafe impl Send for ValueHandle {}
96unsafe impl Sync for ValueHandle {}
97
98impl SqliteValue {
99    pub(crate) unsafe fn new(value: *mut sqlite3_value, type_info: SqliteTypeInfo) -> Self {
100        debug_assert!(!value.is_null());
101
102        Self {
103            type_info,
104            handle: Arc::new(ValueHandle(NonNull::new_unchecked(sqlite3_value_dup(
105                value,
106            )))),
107        }
108    }
109
110    pub fn type_info_opt(&self) -> Option<SqliteTypeInfo> {
111        let dt = DataType::from_code(unsafe { sqlite3_value_type(self.handle.0.as_ptr()) });
112        if let DataType::Null = dt {
113            None
114        } else {
115            Some(SqliteTypeInfo(dt))
116        }
117    }
118
119    pub fn int(&self) -> i32 {
120        unsafe { sqlite3_value_int(self.handle.0.as_ptr()) }
121    }
122
123    pub fn int64(&self) -> i64 {
124        unsafe { sqlite3_value_int64(self.handle.0.as_ptr()) }
125    }
126
127    pub fn double(&self) -> f64 {
128        unsafe { sqlite3_value_double(self.handle.0.as_ptr()) }
129    }
130
131    pub fn blob(&self) -> &[u8] {
132        let len = unsafe { sqlite3_value_bytes(self.handle.0.as_ptr()) } as usize;
133
134        if len == 0 {
135            // empty blobs are NULL so just return an empty slice
136            return &[];
137        }
138
139        let ptr = unsafe { sqlite3_value_blob(self.handle.0.as_ptr()) } as *const u8;
140        debug_assert!(!ptr.is_null());
141
142        unsafe { from_raw_parts(ptr, len) }
143    }
144
145    pub fn text(&self) -> Result<&str, Error> {
146        Ok(from_utf8(self.blob())?)
147    }
148}
149
150impl SqliteValue {
151    pub fn as_ref(&self) -> SqliteValueRef<'_> {
152        SqliteValueRef::value(self)
153    }
154
155    pub fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
156        self.type_info_opt()
157            .map(Cow::Owned)
158            .unwrap_or(Cow::Borrowed(&self.type_info))
159    }
160
161    pub fn is_null(&self) -> bool {
162        unsafe { sqlite3_value_type(self.handle.0.as_ptr()) == SQLITE_NULL }
163    }
164}
165
166impl Drop for ValueHandle {
167    fn drop(&mut self) {
168        unsafe {
169            sqlite3_value_free(self.0.as_ptr());
170        }
171    }
172}