use super::{Type, Value}; use crate::types::{FromSqlError, FromSqlResult}; /// A non-owning [dynamic type value](http://sqlite.org/datatype3.html). Typically the /// memory backing this value is owned by SQLite. /// /// See [`Value`](Value) for an owning dynamic type value. #[derive(Copy, Clone, Debug, PartialEq)] pub enum ValueRef<'a> { /// The value is a `NULL` value. Null, /// The value is a signed integer. Integer(i64), /// The value is a floating point number. Real(f64), /// The value is a text string. Text(&'a [u8]), /// The value is a blob of data Blob(&'a [u8]), } impl ValueRef<'_> { /// Returns SQLite fundamental datatype. #[inline] #[must_use] pub fn data_type(&self) -> Type { match *self { ValueRef::Null => Type::Null, ValueRef::Integer(_) => Type::Integer, ValueRef::Real(_) => Type::Real, ValueRef::Text(_) => Type::Text, ValueRef::Blob(_) => Type::Blob, } } } impl<'a> ValueRef<'a> { /// If `self` is case `Integer`, returns the integral value. Otherwise, /// returns [`Err(Error::InvalidColumnType)`](crate::Error:: /// InvalidColumnType). #[inline] pub fn as_i64(&self) -> FromSqlResult { match *self { ValueRef::Integer(i) => Ok(i), _ => Err(FromSqlError::InvalidType), } } /// If `self` is case `Null` returns None. /// If `self` is case `Integer`, returns the integral value. /// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error:: /// InvalidColumnType). #[inline] pub fn as_i64_or_null(&self) -> FromSqlResult> { match *self { ValueRef::Null => Ok(None), ValueRef::Integer(i) => Ok(Some(i)), _ => Err(FromSqlError::InvalidType), } } /// If `self` is case `Real`, returns the floating point value. Otherwise, /// returns [`Err(Error::InvalidColumnType)`](crate::Error:: /// InvalidColumnType). #[inline] pub fn as_f64(&self) -> FromSqlResult { match *self { ValueRef::Real(f) => Ok(f), _ => Err(FromSqlError::InvalidType), } } /// If `self` is case `Null` returns None. /// If `self` is case `Real`, returns the floating point value. /// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error:: /// InvalidColumnType). #[inline] pub fn as_f64_or_null(&self) -> FromSqlResult> { match *self { ValueRef::Null => Ok(None), ValueRef::Real(f) => Ok(Some(f)), _ => Err(FromSqlError::InvalidType), } } /// If `self` is case `Text`, returns the string value. Otherwise, returns /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). #[inline] pub fn as_str(&self) -> FromSqlResult<&'a str> { match *self { ValueRef::Text(t) => { std::str::from_utf8(t).map_err(|e| FromSqlError::Other(Box::new(e))) } _ => Err(FromSqlError::InvalidType), } } /// If `self` is case `Null` returns None. /// If `self` is case `Text`, returns the string value. /// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error:: /// InvalidColumnType). #[inline] pub fn as_str_or_null(&self) -> FromSqlResult> { match *self { ValueRef::Null => Ok(None), ValueRef::Text(t) => std::str::from_utf8(t) .map_err(|e| FromSqlError::Other(Box::new(e))) .map(Some), _ => Err(FromSqlError::InvalidType), } } /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType). #[inline] pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> { match *self { ValueRef::Blob(b) => Ok(b), _ => Err(FromSqlError::InvalidType), } } /// If `self` is case `Null` returns None. /// If `self` is case `Blob`, returns the byte slice. /// Otherwise returns [`Err(Error::InvalidColumnType)`](crate::Error:: /// InvalidColumnType). #[inline] pub fn as_blob_or_null(&self) -> FromSqlResult> { match *self { ValueRef::Null => Ok(None), ValueRef::Blob(b) => Ok(Some(b)), _ => Err(FromSqlError::InvalidType), } } /// Returns the byte slice that makes up this ValueRef if it's either /// [`ValueRef::Blob`] or [`ValueRef::Text`]. #[inline] pub fn as_bytes(&self) -> FromSqlResult<&'a [u8]> { match self { ValueRef::Text(s) | ValueRef::Blob(s) => Ok(s), _ => Err(FromSqlError::InvalidType), } } /// If `self` is case `Null` returns None. /// If `self` is [`ValueRef::Blob`] or [`ValueRef::Text`] returns the byte /// slice that makes up this value #[inline] pub fn as_bytes_or_null(&self) -> FromSqlResult> { match *self { ValueRef::Null => Ok(None), ValueRef::Text(s) | ValueRef::Blob(s) => Ok(Some(s)), _ => Err(FromSqlError::InvalidType), } } } impl From> for Value { #[inline] fn from(borrowed: ValueRef<'_>) -> Value { match borrowed { ValueRef::Null => Value::Null, ValueRef::Integer(i) => Value::Integer(i), ValueRef::Real(r) => Value::Real(r), ValueRef::Text(s) => { let s = std::str::from_utf8(s).expect("invalid UTF-8"); Value::Text(s.to_string()) } ValueRef::Blob(b) => Value::Blob(b.to_vec()), } } } impl<'a> From<&'a str> for ValueRef<'a> { #[inline] fn from(s: &str) -> ValueRef<'_> { ValueRef::Text(s.as_bytes()) } } impl<'a> From<&'a [u8]> for ValueRef<'a> { #[inline] fn from(s: &[u8]) -> ValueRef<'_> { ValueRef::Blob(s) } } impl<'a> From<&'a Value> for ValueRef<'a> { #[inline] fn from(value: &'a Value) -> ValueRef<'a> { match *value { Value::Null => ValueRef::Null, Value::Integer(i) => ValueRef::Integer(i), Value::Real(r) => ValueRef::Real(r), Value::Text(ref s) => ValueRef::Text(s.as_bytes()), Value::Blob(ref b) => ValueRef::Blob(b), } } } impl<'a, T> From> for ValueRef<'a> where T: Into>, { #[inline] fn from(s: Option) -> ValueRef<'a> { match s { Some(x) => x.into(), None => ValueRef::Null, } } } #[cfg(any(feature = "functions", feature = "session", feature = "vtab"))] impl<'a> ValueRef<'a> { pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a> { use crate::ffi; use std::slice::from_raw_parts; match ffi::sqlite3_value_type(value) { ffi::SQLITE_NULL => ValueRef::Null, ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)), ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)), ffi::SQLITE_TEXT => { let text = ffi::sqlite3_value_text(value); let len = ffi::sqlite3_value_bytes(value); assert!( !text.is_null(), "unexpected SQLITE_TEXT value type with NULL data" ); let s = from_raw_parts(text.cast::(), len as usize); ValueRef::Text(s) } ffi::SQLITE_BLOB => { let (blob, len) = ( ffi::sqlite3_value_blob(value), ffi::sqlite3_value_bytes(value), ); assert!( len >= 0, "unexpected negative return from sqlite3_value_bytes" ); if len > 0 { assert!( !blob.is_null(), "unexpected SQLITE_BLOB value type with NULL data" ); ValueRef::Blob(from_raw_parts(blob.cast::(), len as usize)) } else { // The return value from sqlite3_value_blob() for a zero-length BLOB // is a NULL pointer. ValueRef::Blob(&[]) } } _ => unreachable!("sqlite3_value_type returned invalid value"), } } }