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 is_null(&self) -> bool {
73        match self.0 {
74            SqliteValueData::Value(v) => v.is_null(),
75        }
76    }
77}
78
79#[derive(Clone, Debug)]
80pub struct SqliteValue {
81    pub(crate) handle: Arc<ValueHandle>,
82    pub(crate) type_info: SqliteTypeInfo,
83}
84
85#[derive(Debug)]
86pub(crate) struct ValueHandle(NonNull<sqlite3_value>);
87
88// SAFE: only protected value objects are stored in SqliteValue
89unsafe impl Send for ValueHandle {}
90unsafe impl Sync for ValueHandle {}
91
92impl SqliteValue {
93    pub(crate) unsafe fn new(value: *mut sqlite3_value, type_info: SqliteTypeInfo) -> Self {
94        debug_assert!(!value.is_null());
95
96        Self {
97            type_info,
98            handle: Arc::new(ValueHandle(NonNull::new_unchecked(sqlite3_value_dup(
99                value,
100            )))),
101        }
102    }
103
104    pub fn type_info_opt(&self) -> Option<SqliteTypeInfo> {
105        let dt = DataType::from_code(unsafe { sqlite3_value_type(self.handle.0.as_ptr()) });
106
107        if let DataType::Null = dt {
108            None
109        } else {
110            Some(SqliteTypeInfo(dt))
111        }
112    }
113
114    pub fn int(&self) -> i32 {
115        unsafe { sqlite3_value_int(self.handle.0.as_ptr()) }
116    }
117
118    pub fn int64(&self) -> i64 {
119        unsafe { sqlite3_value_int64(self.handle.0.as_ptr()) }
120    }
121
122    pub fn double(&self) -> f64 {
123        unsafe { sqlite3_value_double(self.handle.0.as_ptr()) }
124    }
125
126    pub fn blob(&self) -> &[u8] {
127        let len = unsafe { sqlite3_value_bytes(self.handle.0.as_ptr()) } as usize;
128
129        if len == 0 {
130            // empty blobs are NULL so just return an empty slice
131            return &[];
132        }
133
134        let ptr = unsafe { sqlite3_value_blob(self.handle.0.as_ptr()) } as *const u8;
135        debug_assert!(!ptr.is_null());
136
137        unsafe { from_raw_parts(ptr, len) }
138    }
139
140    pub fn text(&self) -> Result<&str, Error> {
141        Ok(from_utf8(self.blob())?)
142    }
143}
144
145impl SqliteValue {
146    pub fn as_ref(&self) -> SqliteValueRef<'_> {
147        SqliteValueRef::value(self)
148    }
149
150    pub fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
151        self.type_info_opt()
152            .map(Cow::Owned)
153            .unwrap_or(Cow::Borrowed(&self.type_info))
154    }
155
156    pub fn is_null(&self) -> bool {
157        unsafe { sqlite3_value_type(self.handle.0.as_ptr()) == SQLITE_NULL }
158    }
159}
160
161impl Drop for ValueHandle {
162    fn drop(&mut self) {
163        unsafe {
164            sqlite3_value_free(self.0.as_ptr());
165        }
166    }
167}