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    pub fn data_type(&self) -> Type {
26        match *self {
27            ValueRef::Null => Type::Null,
28            ValueRef::Integer(_) => Type::Integer,
29            ValueRef::Real(_) => Type::Real,
30            ValueRef::Text(_) => Type::Text,
31            ValueRef::Blob(_) => Type::Blob,
32        }
33    }
34}
35
36impl<'a> ValueRef<'a> {
37    /// If `self` is case `Integer`, returns the integral value. Otherwise,
38    /// returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
39    #[inline]
40    pub fn as_i64(&self) -> FromSqlResult<i64> {
41        match *self {
42            ValueRef::Integer(i) => Ok(i),
43            _ => Err(FromSqlError::InvalidType),
44        }
45    }
46
47    /// If `self` is case `Real`, returns the floating point value. Otherwise,
48    /// returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
49    #[inline]
50    pub fn as_f64(&self) -> FromSqlResult<f64> {
51        match *self {
52            ValueRef::Real(f) => Ok(f),
53            _ => Err(FromSqlError::InvalidType),
54        }
55    }
56
57    /// If `self` is case `Text`, returns the string value. Otherwise, returns
58    /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
59    #[inline]
60    pub fn as_str(&self) -> FromSqlResult<&'a str> {
61        match *self {
62            ValueRef::Text(t) => {
63                std::str::from_utf8(t).map_err(|e| FromSqlError::Other(Box::new(e)))
64            }
65            _ => Err(FromSqlError::InvalidType),
66        }
67    }
68
69    /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
70    /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
71    #[inline]
72    pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
73        match *self {
74            ValueRef::Blob(b) => Ok(b),
75            _ => Err(FromSqlError::InvalidType),
76        }
77    }
78}
79
80impl From<ValueRef<'_>> for Value {
81    #[inline]
82    fn from(borrowed: ValueRef<'_>) -> Value {
83        match borrowed {
84            ValueRef::Null => Value::Null,
85            ValueRef::Integer(i) => Value::Integer(i),
86            ValueRef::Real(r) => Value::Real(r),
87            ValueRef::Text(s) => {
88                let s = std::str::from_utf8(s).expect("invalid UTF-8");
89                Value::Text(s.to_string())
90            }
91            ValueRef::Blob(b) => Value::Blob(b.to_vec()),
92        }
93    }
94}
95
96impl<'a> From<&'a str> for ValueRef<'a> {
97    #[inline]
98    fn from(s: &str) -> ValueRef<'_> {
99        ValueRef::Text(s.as_bytes())
100    }
101}
102
103impl<'a> From<&'a [u8]> for ValueRef<'a> {
104    #[inline]
105    fn from(s: &[u8]) -> ValueRef<'_> {
106        ValueRef::Blob(s)
107    }
108}
109
110impl<'a> From<&'a Value> for ValueRef<'a> {
111    #[inline]
112    fn from(value: &'a Value) -> ValueRef<'a> {
113        match *value {
114            Value::Null => ValueRef::Null,
115            Value::Integer(i) => ValueRef::Integer(i),
116            Value::Real(r) => ValueRef::Real(r),
117            Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
118            Value::Blob(ref b) => ValueRef::Blob(b),
119        }
120    }
121}
122
123impl<'a, T> From<Option<T>> for ValueRef<'a>
124where
125    T: Into<ValueRef<'a>>,
126{
127    #[inline]
128    fn from(s: Option<T>) -> ValueRef<'a> {
129        match s {
130            Some(x) => x.into(),
131            None => ValueRef::Null,
132        }
133    }
134}
135
136#[cfg(any(feature = "functions", feature = "session", feature = "vtab"))]
137impl<'a> ValueRef<'a> {
138    pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a> {
139        use crate::ffi;
140        use std::slice::from_raw_parts;
141
142        match ffi::sqlite3_value_type(value) {
143            ffi::SQLITE_NULL => ValueRef::Null,
144            ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)),
145            ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)),
146            ffi::SQLITE_TEXT => {
147                let text = ffi::sqlite3_value_text(value);
148                let len = ffi::sqlite3_value_bytes(value);
149                assert!(
150                    !text.is_null(),
151                    "unexpected SQLITE_TEXT value type with NULL data"
152                );
153                let s = from_raw_parts(text as *const u8, len as usize);
154                ValueRef::Text(s)
155            }
156            ffi::SQLITE_BLOB => {
157                let (blob, len) = (
158                    ffi::sqlite3_value_blob(value),
159                    ffi::sqlite3_value_bytes(value),
160                );
161
162                assert!(
163                    len >= 0,
164                    "unexpected negative return from sqlite3_value_bytes"
165                );
166                if len > 0 {
167                    assert!(
168                        !blob.is_null(),
169                        "unexpected SQLITE_BLOB value type with NULL data"
170                    );
171                    ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize))
172                } else {
173                    // The return value from sqlite3_value_blob() for a zero-length BLOB
174                    // is a NULL pointer.
175                    ValueRef::Blob(&[])
176                }
177            }
178            _ => unreachable!("sqlite3_value_type returned invalid value"),
179        }
180    }
181}