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    fn from(borrowed: ValueRef<'_>) -> Value {
162        match borrowed {
163            ValueRef::Null => Value::Null,
164            ValueRef::Integer(i) => Value::Integer(i),
165            ValueRef::Real(r) => Value::Real(r),
166            ValueRef::Text(s) => {
167                let s = std::str::from_utf8(s).expect("invalid UTF-8");
168                Value::Text(s.to_string())
169            }
170            ValueRef::Blob(b) => Value::Blob(b.to_vec()),
171        }
172    }
173}
174
175impl<'a> From<&'a str> for ValueRef<'a> {
176    #[inline]
177    fn from(s: &str) -> ValueRef<'_> {
178        ValueRef::Text(s.as_bytes())
179    }
180}
181
182impl<'a> From<&'a [u8]> for ValueRef<'a> {
183    #[inline]
184    fn from(s: &[u8]) -> ValueRef<'_> {
185        ValueRef::Blob(s)
186    }
187}
188
189impl<'a> From<&'a Value> for ValueRef<'a> {
190    #[inline]
191    fn from(value: &'a Value) -> ValueRef<'a> {
192        match *value {
193            Value::Null => ValueRef::Null,
194            Value::Integer(i) => ValueRef::Integer(i),
195            Value::Real(r) => ValueRef::Real(r),
196            Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
197            Value::Blob(ref b) => ValueRef::Blob(b),
198        }
199    }
200}
201
202impl<'a, T> From<Option<T>> for ValueRef<'a>
203where
204    T: Into<ValueRef<'a>>,
205{
206    #[inline]
207    fn from(s: Option<T>) -> ValueRef<'a> {
208        match s {
209            Some(x) => x.into(),
210            None => ValueRef::Null,
211        }
212    }
213}
214
215#[cfg(any(feature = "functions", feature = "session", feature = "vtab"))]
216impl<'a> ValueRef<'a> {
217    pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a> {
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}