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