Skip to main content

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(FromSqlError::InvalidType)`](FromSqlError::InvalidType).
40    #[inline]
41    pub fn as_i64(&self) -> FromSqlResult<i64> {
42        match *self {
43            ValueRef::Integer(i) => Ok(i),
44            _ => Err(FromSqlError::InvalidType),
45        }
46    }
47
48    /// If `self` is case `Null` returns None.
49    /// If `self` is case `Integer`, returns the integral value.
50    /// Otherwise, returns [`Err(FromSqlError::InvalidType)`](FromSqlError::InvalidType).
51    #[inline]
52    pub fn as_i64_or_null(&self) -> FromSqlResult<Option<i64>> {
53        match *self {
54            ValueRef::Null => Ok(None),
55            ValueRef::Integer(i) => Ok(Some(i)),
56            _ => Err(FromSqlError::InvalidType),
57        }
58    }
59
60    /// If `self` is case `Real`, returns the floating point value. Otherwise,
61    /// returns [`Err(FromSqlError::InvalidType)`](FromSqlError::InvalidType).
62    #[inline]
63    pub fn as_f64(&self) -> FromSqlResult<f64> {
64        match *self {
65            ValueRef::Real(f) => Ok(f),
66            _ => Err(FromSqlError::InvalidType),
67        }
68    }
69
70    /// If `self` is case `Null` returns None.
71    /// If `self` is case `Real`, returns the floating point value.
72    /// Otherwise, returns [`Err(FromSqlError::InvalidType)`](FromSqlError::InvalidType).
73    #[inline]
74    pub fn as_f64_or_null(&self) -> FromSqlResult<Option<f64>> {
75        match *self {
76            ValueRef::Null => Ok(None),
77            ValueRef::Real(f) => Ok(Some(f)),
78            _ => Err(FromSqlError::InvalidType),
79        }
80    }
81
82    /// If `self` is case `Text`, returns the string value. Otherwise, returns
83    /// [`Err(FromSqlError::InvalidType)`](FromSqlError::InvalidType).
84    #[inline]
85    pub fn as_str(&self) -> FromSqlResult<&'a str> {
86        match *self {
87            ValueRef::Text(t) => std::str::from_utf8(t).map_err(FromSqlError::Utf8Error),
88            _ => Err(FromSqlError::InvalidType),
89        }
90    }
91
92    /// If `self` is case `Null` returns None.
93    /// If `self` is case `Text`, returns the string value.
94    /// Otherwise, returns [`Err(FromSqlError::InvalidType)`](FromSqlError::InvalidType).
95    #[inline]
96    pub fn as_str_or_null(&self) -> FromSqlResult<Option<&'a str>> {
97        match *self {
98            ValueRef::Null => Ok(None),
99            ValueRef::Text(t) => std::str::from_utf8(t)
100                .map_err(FromSqlError::Utf8Error)
101                .map(Some),
102            _ => Err(FromSqlError::InvalidType),
103        }
104    }
105
106    /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
107    /// [`Err(FromSqlError::InvalidType)`](FromSqlError::InvalidType).
108    #[inline]
109    pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
110        match *self {
111            ValueRef::Blob(b) => Ok(b),
112            _ => Err(FromSqlError::InvalidType),
113        }
114    }
115
116    /// If `self` is case `Null` returns None.
117    /// If `self` is case `Blob`, returns the byte slice.
118    /// Otherwise, returns [`Err(FromSqlError::InvalidType)`](FromSqlError::InvalidType).
119    #[inline]
120    pub fn as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
121        match *self {
122            ValueRef::Null => Ok(None),
123            ValueRef::Blob(b) => Ok(Some(b)),
124            _ => Err(FromSqlError::InvalidType),
125        }
126    }
127
128    /// Returns the byte slice that makes up this `ValueRef` if it's either
129    /// [`ValueRef::Blob`] or [`ValueRef::Text`].
130    #[inline]
131    pub fn as_bytes(&self) -> FromSqlResult<&'a [u8]> {
132        match self {
133            ValueRef::Text(s) | ValueRef::Blob(s) => Ok(s),
134            _ => Err(FromSqlError::InvalidType),
135        }
136    }
137
138    /// If `self` is case `Null` returns None.
139    /// If `self` is [`ValueRef::Blob`] or [`ValueRef::Text`] returns the byte
140    /// slice that makes up this value
141    #[inline]
142    pub fn as_bytes_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
143        match *self {
144            ValueRef::Null => Ok(None),
145            ValueRef::Text(s) | ValueRef::Blob(s) => Ok(Some(s)),
146            _ => Err(FromSqlError::InvalidType),
147        }
148    }
149}
150
151impl TryFrom<ValueRef<'_>> for Value {
152    type Error = FromSqlError;
153
154    #[inline]
155    #[track_caller]
156    fn try_from(borrowed: ValueRef<'_>) -> Result<Self, Self::Error> {
157        match borrowed {
158            ValueRef::Null => Ok(Self::Null),
159            ValueRef::Integer(i) => Ok(Self::Integer(i)),
160            ValueRef::Real(r) => Ok(Self::Real(r)),
161            ValueRef::Text(s) => std::str::from_utf8(s)
162                .map(|s| Self::Text(s.to_string()))
163                .map_err(FromSqlError::Utf8Error),
164            ValueRef::Blob(b) => Ok(Self::Blob(b.to_vec())),
165        }
166    }
167}
168
169impl<'a> From<&'a str> for ValueRef<'a> {
170    #[inline]
171    fn from(s: &str) -> ValueRef<'_> {
172        ValueRef::Text(s.as_bytes())
173    }
174}
175
176impl<'a> From<&'a [u8]> for ValueRef<'a> {
177    #[inline]
178    fn from(s: &[u8]) -> ValueRef<'_> {
179        ValueRef::Blob(s)
180    }
181}
182
183impl<'a> From<&'a Value> for ValueRef<'a> {
184    #[inline]
185    fn from(value: &'a Value) -> Self {
186        match *value {
187            Value::Null => ValueRef::Null,
188            Value::Integer(i) => ValueRef::Integer(i),
189            Value::Real(r) => ValueRef::Real(r),
190            Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
191            Value::Blob(ref b) => ValueRef::Blob(b),
192        }
193    }
194}
195
196impl<T> From<Option<T>> for ValueRef<'_>
197where
198    T: Into<Self>,
199{
200    #[inline]
201    fn from(s: Option<T>) -> Self {
202        match s {
203            Some(x) => x.into(),
204            None => ValueRef::Null,
205        }
206    }
207}
208
209#[cfg(any(
210    feature = "functions",
211    feature = "session",
212    feature = "vtab",
213    feature = "preupdate_hook"
214))]
215impl ValueRef<'_> {
216    pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> Self {
217        use crate::ffi;
218        use std::slice::from_raw_parts;
219
220        match ffi::sqlite3_value_type(value) {
221            ffi::SQLITE_NULL => ValueRef::Null,
222            ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)),
223            ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)),
224            ffi::SQLITE_TEXT => {
225                let text = ffi::sqlite3_value_text(value);
226                let len = ffi::sqlite3_value_bytes(value);
227                assert!(
228                    !text.is_null(),
229                    "unexpected SQLITE_TEXT value type with NULL data"
230                );
231                let s = from_raw_parts(text.cast::<u8>(), len as usize);
232                ValueRef::Text(s)
233            }
234            ffi::SQLITE_BLOB => {
235                let (blob, len) = (
236                    ffi::sqlite3_value_blob(value),
237                    ffi::sqlite3_value_bytes(value),
238                );
239
240                assert!(
241                    len >= 0,
242                    "unexpected negative return from sqlite3_value_bytes"
243                );
244                if len > 0 {
245                    assert!(
246                        !blob.is_null(),
247                        "unexpected SQLITE_BLOB value type with NULL data"
248                    );
249                    ValueRef::Blob(from_raw_parts(blob.cast::<u8>(), len as usize))
250                } else {
251                    // The return value from sqlite3_value_blob() for a zero-length BLOB
252                    // is a NULL pointer.
253                    ValueRef::Blob(&[])
254                }
255            }
256            _ => unreachable!("sqlite3_value_type returned invalid value"),
257        }
258    }
259
260    // TODO sqlite3_value_frombind // 3.28.0
261}
262
263#[cfg(test)]
264mod test {
265    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
266    use wasm_bindgen_test::wasm_bindgen_test as test;
267
268    use super::ValueRef;
269    use crate::types::FromSqlResult;
270
271    #[test]
272    fn as_i64() -> FromSqlResult<()> {
273        assert!(ValueRef::Real(1.0).as_i64().is_err());
274        assert_eq!(ValueRef::Integer(1).as_i64(), Ok(1));
275        Ok(())
276    }
277    #[test]
278    fn as_i64_or_null() -> FromSqlResult<()> {
279        assert_eq!(ValueRef::Null.as_i64_or_null(), Ok(None));
280        assert!(ValueRef::Real(1.0).as_i64_or_null().is_err());
281        assert_eq!(ValueRef::Integer(1).as_i64_or_null(), Ok(Some(1)));
282        Ok(())
283    }
284    #[test]
285    fn as_f64() -> FromSqlResult<()> {
286        assert!(ValueRef::Integer(1).as_f64().is_err());
287        assert_eq!(ValueRef::Real(1.0).as_f64(), Ok(1.0));
288        Ok(())
289    }
290    #[test]
291    fn as_f64_or_null() -> FromSqlResult<()> {
292        assert_eq!(ValueRef::Null.as_f64_or_null(), Ok(None));
293        assert!(ValueRef::Integer(1).as_f64_or_null().is_err());
294        assert_eq!(ValueRef::Real(1.0).as_f64_or_null(), Ok(Some(1.0)));
295        Ok(())
296    }
297    #[test]
298    fn as_str() -> FromSqlResult<()> {
299        assert!(ValueRef::Null.as_str().is_err());
300        assert_eq!(ValueRef::Text(b"").as_str(), Ok(""));
301        Ok(())
302    }
303    #[test]
304    fn as_str_or_null() -> FromSqlResult<()> {
305        assert_eq!(ValueRef::Null.as_str_or_null(), Ok(None));
306        assert!(ValueRef::Integer(1).as_str_or_null().is_err());
307        assert_eq!(ValueRef::Text(b"").as_str_or_null(), Ok(Some("")));
308        Ok(())
309    }
310    #[test]
311    fn as_blob() -> FromSqlResult<()> {
312        assert!(ValueRef::Null.as_blob().is_err());
313        assert_eq!(ValueRef::Blob(b"").as_blob(), Ok(&b""[..]));
314        Ok(())
315    }
316    #[test]
317    fn as_blob_or_null() -> FromSqlResult<()> {
318        assert_eq!(ValueRef::Null.as_blob_or_null(), Ok(None));
319        assert!(ValueRef::Integer(1).as_blob_or_null().is_err());
320        assert_eq!(ValueRef::Blob(b"").as_blob_or_null(), Ok(Some(&b""[..])));
321        Ok(())
322    }
323    #[test]
324    fn as_bytes() -> FromSqlResult<()> {
325        assert!(ValueRef::Null.as_bytes().is_err());
326        assert_eq!(ValueRef::Blob(b"").as_bytes(), Ok(&b""[..]));
327        Ok(())
328    }
329    #[test]
330    fn as_bytes_or_null() -> FromSqlResult<()> {
331        assert_eq!(ValueRef::Null.as_bytes_or_null(), Ok(None));
332        assert!(ValueRef::Integer(1).as_bytes_or_null().is_err());
333        assert_eq!(ValueRef::Blob(b"").as_bytes_or_null(), Ok(Some(&b""[..])));
334        Ok(())
335    }
336    #[test]
337    fn from_value() {
338        use crate::types::Value;
339        assert_eq!(
340            ValueRef::from(&Value::Text("".to_owned())),
341            ValueRef::Text(b"")
342        );
343        assert_eq!(ValueRef::from(&Value::Blob(vec![])), ValueRef::Blob(b""));
344    }
345    #[test]
346    fn from_option() {
347        assert_eq!(ValueRef::from(None as Option<&str>), ValueRef::Null);
348        assert_eq!(ValueRef::from(Some("")), ValueRef::Text(b""));
349    }
350}