1use 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) => std::str::from_utf8(t).map_err(FromSqlError::Utf8Error),
88 _ => Err(FromSqlError::InvalidType),
89 }
90 }
91
92 #[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 #[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 #[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 #[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 #[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 ValueRef::Blob(&[])
254 }
255 }
256 _ => unreachable!("sqlite3_value_type returned invalid value"),
257 }
258 }
259
260 }
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}