rusqlite/types/
value_ref.rs1use super::{Type, Value};
2use crate::types::{FromSqlError, FromSqlResult};
3
4#[derive(Copy, Clone, Debug, PartialEq)]
9pub enum ValueRef<'a> {
10 Null,
12 Integer(i64),
14 Real(f64),
16 Text(&'a [u8]),
18 Blob(&'a [u8]),
20}
21
22impl ValueRef<'_> {
23 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 ValueRef::Blob(&[])
255 }
256 }
257 _ => unreachable!("sqlite3_value_type returned invalid value"),
258 }
259 }
260
261 }
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}