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) => Ok(std::str::from_utf8(t)?),
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) => Ok(Some(std::str::from_utf8(t)?)),
100 _ => Err(FromSqlError::InvalidType),
101 }
102 }
103
104 #[inline]
107 pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
108 match *self {
109 ValueRef::Blob(b) => Ok(b),
110 _ => Err(FromSqlError::InvalidType),
111 }
112 }
113
114 #[inline]
118 pub fn as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
119 match *self {
120 ValueRef::Null => Ok(None),
121 ValueRef::Blob(b) => Ok(Some(b)),
122 _ => Err(FromSqlError::InvalidType),
123 }
124 }
125
126 #[inline]
129 pub fn as_bytes(&self) -> FromSqlResult<&'a [u8]> {
130 match self {
131 ValueRef::Text(s) | ValueRef::Blob(s) => Ok(s),
132 _ => Err(FromSqlError::InvalidType),
133 }
134 }
135
136 #[inline]
140 pub fn as_bytes_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
141 match *self {
142 ValueRef::Null => Ok(None),
143 ValueRef::Text(s) | ValueRef::Blob(s) => Ok(Some(s)),
144 _ => Err(FromSqlError::InvalidType),
145 }
146 }
147}
148
149impl TryFrom<ValueRef<'_>> for Value {
150 type Error = FromSqlError;
151
152 #[inline]
153 #[track_caller]
154 fn try_from(borrowed: ValueRef<'_>) -> Result<Self, Self::Error> {
155 Ok(match borrowed {
156 ValueRef::Null => Self::Null,
157 ValueRef::Integer(i) => Self::Integer(i),
158 ValueRef::Real(r) => Self::Real(r),
159 ValueRef::Text(s) => Self::Text(std::str::from_utf8(s)?.to_owned()),
160 ValueRef::Blob(b) => Self::Blob(b.to_vec()),
161 })
162 }
163}
164
165impl<'a> From<&'a str> for ValueRef<'a> {
166 #[inline]
167 fn from(s: &str) -> ValueRef<'_> {
168 ValueRef::Text(s.as_bytes())
169 }
170}
171
172impl<'a> From<&'a [u8]> for ValueRef<'a> {
173 #[inline]
174 fn from(s: &[u8]) -> ValueRef<'_> {
175 ValueRef::Blob(s)
176 }
177}
178
179impl<'a> From<&'a Value> for ValueRef<'a> {
180 #[inline]
181 fn from(value: &'a Value) -> Self {
182 match *value {
183 Value::Null => ValueRef::Null,
184 Value::Integer(i) => ValueRef::Integer(i),
185 Value::Real(r) => ValueRef::Real(r),
186 Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
187 Value::Blob(ref b) => ValueRef::Blob(b),
188 }
189 }
190}
191
192impl<T> From<Option<T>> for ValueRef<'_>
193where
194 T: Into<Self>,
195{
196 #[inline]
197 fn from(s: Option<T>) -> Self {
198 match s {
199 Some(x) => x.into(),
200 None => ValueRef::Null,
201 }
202 }
203}
204
205#[cfg(any(
206 feature = "functions",
207 feature = "session",
208 feature = "vtab",
209 feature = "preupdate_hook"
210))]
211impl ValueRef<'_> {
212 pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> Self {
213 use crate::ffi;
214 use crate::util::from_raw_parts;
215
216 unsafe {
217 match ffi::sqlite3_value_type(value) {
218 ffi::SQLITE_NULL => ValueRef::Null,
219 ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)),
220 ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)),
221 ffi::SQLITE_TEXT => {
222 let text = ffi::sqlite3_value_text(value);
223 let len = ffi::sqlite3_value_bytes(value);
224 assert!(
225 !text.is_null(),
226 "unexpected SQLITE_TEXT value type with NULL data"
227 );
228 let s = from_raw_parts(text.cast::<u8>(), len);
229 ValueRef::Text(s)
230 }
231 ffi::SQLITE_BLOB => {
232 let (blob, len) = (
233 ffi::sqlite3_value_blob(value),
234 ffi::sqlite3_value_bytes(value),
235 );
236
237 assert!(
238 len >= 0,
239 "unexpected negative return from sqlite3_value_bytes"
240 );
241 if len > 0 {
242 assert!(
243 !blob.is_null(),
244 "unexpected SQLITE_BLOB value type with NULL data"
245 );
246 ValueRef::Blob(from_raw_parts(blob.cast::<u8>(), len))
247 } else {
248 ValueRef::Blob(&[])
251 }
252 }
253 _ => unreachable!("sqlite3_value_type returned invalid value"),
254 }
255 }
256 }
257
258 }
260
261#[cfg(test)]
262mod test {
263 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
264 use wasm_bindgen_test::wasm_bindgen_test as test;
265
266 use super::ValueRef;
267 use crate::types::FromSqlResult;
268
269 #[test]
270 fn as_i64() -> FromSqlResult<()> {
271 assert!(ValueRef::Real(1.0).as_i64().is_err());
272 assert_eq!(ValueRef::Integer(1).as_i64(), Ok(1));
273 Ok(())
274 }
275 #[test]
276 fn as_i64_or_null() -> FromSqlResult<()> {
277 assert_eq!(ValueRef::Null.as_i64_or_null(), Ok(None));
278 assert!(ValueRef::Real(1.0).as_i64_or_null().is_err());
279 assert_eq!(ValueRef::Integer(1).as_i64_or_null(), Ok(Some(1)));
280 Ok(())
281 }
282 #[test]
283 fn as_f64() -> FromSqlResult<()> {
284 assert!(ValueRef::Integer(1).as_f64().is_err());
285 assert_eq!(ValueRef::Real(1.0).as_f64(), Ok(1.0));
286 Ok(())
287 }
288 #[test]
289 fn as_f64_or_null() -> FromSqlResult<()> {
290 assert_eq!(ValueRef::Null.as_f64_or_null(), Ok(None));
291 assert!(ValueRef::Integer(1).as_f64_or_null().is_err());
292 assert_eq!(ValueRef::Real(1.0).as_f64_or_null(), Ok(Some(1.0)));
293 Ok(())
294 }
295 #[test]
296 fn as_str() -> FromSqlResult<()> {
297 assert!(ValueRef::Null.as_str().is_err());
298 assert_eq!(ValueRef::Text(b"").as_str(), Ok(""));
299 Ok(())
300 }
301 #[test]
302 fn as_str_or_null() -> FromSqlResult<()> {
303 assert_eq!(ValueRef::Null.as_str_or_null(), Ok(None));
304 assert!(ValueRef::Integer(1).as_str_or_null().is_err());
305 assert_eq!(ValueRef::Text(b"").as_str_or_null(), Ok(Some("")));
306 Ok(())
307 }
308 #[test]
309 fn as_blob() -> FromSqlResult<()> {
310 assert!(ValueRef::Null.as_blob().is_err());
311 assert_eq!(ValueRef::Blob(b"").as_blob(), Ok(&b""[..]));
312 Ok(())
313 }
314 #[test]
315 fn as_blob_or_null() -> FromSqlResult<()> {
316 assert_eq!(ValueRef::Null.as_blob_or_null(), Ok(None));
317 assert!(ValueRef::Integer(1).as_blob_or_null().is_err());
318 assert_eq!(ValueRef::Blob(b"").as_blob_or_null(), Ok(Some(&b""[..])));
319 Ok(())
320 }
321 #[test]
322 fn as_bytes() -> FromSqlResult<()> {
323 assert!(ValueRef::Null.as_bytes().is_err());
324 assert_eq!(ValueRef::Blob(b"").as_bytes(), Ok(&b""[..]));
325 Ok(())
326 }
327 #[test]
328 fn as_bytes_or_null() -> FromSqlResult<()> {
329 assert_eq!(ValueRef::Null.as_bytes_or_null(), Ok(None));
330 assert!(ValueRef::Integer(1).as_bytes_or_null().is_err());
331 assert_eq!(ValueRef::Blob(b"").as_bytes_or_null(), Ok(Some(&b""[..])));
332 Ok(())
333 }
334 #[test]
335 fn from_value() {
336 use crate::types::Value;
337 assert_eq!(
338 ValueRef::from(&Value::Text("".to_owned())),
339 ValueRef::Text(b"")
340 );
341 assert_eq!(ValueRef::from(&Value::Blob(vec![])), ValueRef::Blob(b""));
342 }
343 #[test]
344 fn from_option() {
345 assert_eq!(ValueRef::from(None as Option<&str>), ValueRef::Null);
346 assert_eq!(ValueRef::from(Some("")), ValueRef::Text(b""));
347 }
348}