rusqlite/types/
value_ref.rs

1use super::{Type, Value};
2use crate::types::{FromSqlError, FromSqlResult};
3
4/// A non-owning [dynamic type value](http://sqlite.org/datatype3.html). Typically the
5/// memory backing this value is owned by SQLite.
6///
7/// See [`Value`](Value) for an owning dynamic type value.
8#[derive(Copy, Clone, Debug, PartialEq)]
9pub enum ValueRef<'a> {
10    /// The value is a `NULL` value.
11    Null,
12    /// The value is a signed integer.
13    Integer(i64),
14    /// The value is a floating point number.
15    Real(f64),
16    /// The value is a text string.
17    Text(&'a [u8]),
18    /// The value is a blob of data
19    Blob(&'a [u8]),
20}
21
22impl ValueRef<'_> {
23    /// Returns SQLite fundamental datatype.
24    #[inline]
25    #[must_use]
26    pub fn data_type(&self) -> Type {
27        match *self {
28            ValueRef::Null => Type::Null,
29            ValueRef::Integer(_) => Type::Integer,
30            ValueRef::Real(_) => Type::Real,
31            ValueRef::Text(_) => Type::Text,
32            ValueRef::Blob(_) => Type::Blob,
33        }
34    }
35}
36
37impl<'a> ValueRef<'a> {
38    /// If `self` is case `Integer`, returns the integral value. Otherwise,
39    /// returns [`Err(Error::InvalidColumnType)`](crate::Error::
40    /// InvalidColumnType).
41    #[inline]
42    pub fn as_i64(&self) -> FromSqlResult<i64> {
43        match *self {
44            ValueRef::Integer(i) => Ok(i),
45            _ => Err(FromSqlError::InvalidType),
46        }
47    }
48
49    /// If `self` is case `Null` returns None.
50    /// If `self` is case `Integer`, returns the integral value.
51    /// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error::
52    /// InvalidColumnType).
53    #[inline]
54    pub fn as_i64_or_null(&self) -> FromSqlResult<Option<i64>> {
55        match *self {
56            ValueRef::Null => Ok(None),
57            ValueRef::Integer(i) => Ok(Some(i)),
58            _ => Err(FromSqlError::InvalidType),
59        }
60    }
61
62    /// If `self` is case `Real`, returns the floating point value. Otherwise,
63    /// returns [`Err(Error::InvalidColumnType)`](crate::Error::
64    /// InvalidColumnType).
65    #[inline]
66    pub fn as_f64(&self) -> FromSqlResult<f64> {
67        match *self {
68            ValueRef::Real(f) => Ok(f),
69            _ => Err(FromSqlError::InvalidType),
70        }
71    }
72
73    /// If `self` is case `Null` returns None.
74    /// If `self` is case `Real`, returns the floating point value.
75    /// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error::
76    /// InvalidColumnType).
77    #[inline]
78    pub fn as_f64_or_null(&self) -> FromSqlResult<Option<f64>> {
79        match *self {
80            ValueRef::Null => Ok(None),
81            ValueRef::Real(f) => Ok(Some(f)),
82            _ => Err(FromSqlError::InvalidType),
83        }
84    }
85
86    /// If `self` is case `Text`, returns the string value. Otherwise, returns
87    /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
88    #[inline]
89    pub fn as_str(&self) -> FromSqlResult<&'a str> {
90        match *self {
91            ValueRef::Text(t) => {
92                std::str::from_utf8(t).map_err(|e| FromSqlError::Other(Box::new(e)))
93            }
94            _ => Err(FromSqlError::InvalidType),
95        }
96    }
97
98    /// If `self` is case `Null` returns None.
99    /// If `self` is case `Text`, returns the string value.
100    /// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error::
101    /// InvalidColumnType).
102    #[inline]
103    pub fn as_str_or_null(&self) -> FromSqlResult<Option<&'a str>> {
104        match *self {
105            ValueRef::Null => Ok(None),
106            ValueRef::Text(t) => std::str::from_utf8(t)
107                .map_err(|e| FromSqlError::Other(Box::new(e)))
108                .map(Some),
109            _ => Err(FromSqlError::InvalidType),
110        }
111    }
112
113    /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
114    /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
115    #[inline]
116    pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
117        match *self {
118            ValueRef::Blob(b) => Ok(b),
119            _ => Err(FromSqlError::InvalidType),
120        }
121    }
122
123    /// If `self` is case `Null` returns None.
124    /// If `self` is case `Blob`, returns the byte slice.
125    /// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error::
126    /// InvalidColumnType).
127    #[inline]
128    pub fn as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
129        match *self {
130            ValueRef::Null => Ok(None),
131            ValueRef::Blob(b) => Ok(Some(b)),
132            _ => Err(FromSqlError::InvalidType),
133        }
134    }
135
136    /// Returns the byte slice that makes up this ValueRef if it's either
137    /// [`ValueRef::Blob`] or [`ValueRef::Text`].
138    #[inline]
139    pub fn as_bytes(&self) -> FromSqlResult<&'a [u8]> {
140        match self {
141            ValueRef::Text(s) | ValueRef::Blob(s) => Ok(s),
142            _ => Err(FromSqlError::InvalidType),
143        }
144    }
145
146    /// If `self` is case `Null` returns None.
147    /// If `self` is [`ValueRef::Blob`] or [`ValueRef::Text`] returns the byte
148    /// slice that makes up this value
149    #[inline]
150    pub fn as_bytes_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
151        match *self {
152            ValueRef::Null => Ok(None),
153            ValueRef::Text(s) | ValueRef::Blob(s) => Ok(Some(s)),
154            _ => Err(FromSqlError::InvalidType),
155        }
156    }
157}
158
159impl From<ValueRef<'_>> for Value {
160    #[inline]
161    #[track_caller]
162    fn from(borrowed: ValueRef<'_>) -> Value {
163        match borrowed {
164            ValueRef::Null => Value::Null,
165            ValueRef::Integer(i) => Value::Integer(i),
166            ValueRef::Real(r) => Value::Real(r),
167            ValueRef::Text(s) => {
168                let s = std::str::from_utf8(s).expect("invalid UTF-8");
169                Value::Text(s.to_string())
170            }
171            ValueRef::Blob(b) => Value::Blob(b.to_vec()),
172        }
173    }
174}
175
176impl<'a> From<&'a str> for ValueRef<'a> {
177    #[inline]
178    fn from(s: &str) -> ValueRef<'_> {
179        ValueRef::Text(s.as_bytes())
180    }
181}
182
183impl<'a> From<&'a [u8]> for ValueRef<'a> {
184    #[inline]
185    fn from(s: &[u8]) -> ValueRef<'_> {
186        ValueRef::Blob(s)
187    }
188}
189
190impl<'a> From<&'a Value> for ValueRef<'a> {
191    #[inline]
192    fn from(value: &'a Value) -> ValueRef<'a> {
193        match *value {
194            Value::Null => ValueRef::Null,
195            Value::Integer(i) => ValueRef::Integer(i),
196            Value::Real(r) => ValueRef::Real(r),
197            Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
198            Value::Blob(ref b) => ValueRef::Blob(b),
199        }
200    }
201}
202
203impl<'a, T> From<Option<T>> for ValueRef<'a>
204where
205    T: Into<ValueRef<'a>>,
206{
207    #[inline]
208    fn from(s: Option<T>) -> ValueRef<'a> {
209        match s {
210            Some(x) => x.into(),
211            None => ValueRef::Null,
212        }
213    }
214}
215
216#[cfg(any(feature = "functions", feature = "session", feature = "vtab"))]
217impl<'a> ValueRef<'a> {
218    pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a> {
219        use crate::ffi;
220        use std::slice::from_raw_parts;
221
222        match ffi::sqlite3_value_type(value) {
223            ffi::SQLITE_NULL => ValueRef::Null,
224            ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)),
225            ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)),
226            ffi::SQLITE_TEXT => {
227                let text = ffi::sqlite3_value_text(value);
228                let len = ffi::sqlite3_value_bytes(value);
229                assert!(
230                    !text.is_null(),
231                    "unexpected SQLITE_TEXT value type with NULL data"
232                );
233                let s = from_raw_parts(text.cast::<u8>(), len as usize);
234                ValueRef::Text(s)
235            }
236            ffi::SQLITE_BLOB => {
237                let (blob, len) = (
238                    ffi::sqlite3_value_blob(value),
239                    ffi::sqlite3_value_bytes(value),
240                );
241
242                assert!(
243                    len >= 0,
244                    "unexpected negative return from sqlite3_value_bytes"
245                );
246                if len > 0 {
247                    assert!(
248                        !blob.is_null(),
249                        "unexpected SQLITE_BLOB value type with NULL data"
250                    );
251                    ValueRef::Blob(from_raw_parts(blob.cast::<u8>(), len as usize))
252                } else {
253                    // The return value from sqlite3_value_blob() for a zero-length BLOB
254                    // is a NULL pointer.
255                    ValueRef::Blob(&[])
256                }
257            }
258            _ => unreachable!("sqlite3_value_type returned invalid value"),
259        }
260    }
261
262    // TODO sqlite3_value_nochange // 3.22.0 & VTab xUpdate
263    // TODO sqlite3_value_frombind // 3.28.0
264}