#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Null,
Bool(bool),
I64(i64),
F64(f64),
Text(String),
Bytes(Vec<u8>),
#[cfg(feature = "json")]
Json(serde_json::Value),
#[cfg(feature = "uuid")]
Uuid(uuid::Uuid),
#[cfg(feature = "chrono")]
DateTimeUtc(chrono::DateTime<chrono::Utc>),
#[cfg(feature = "chrono")]
NaiveDateTime(chrono::NaiveDateTime),
#[cfg(feature = "chrono")]
NaiveDate(chrono::NaiveDate),
#[cfg(feature = "chrono")]
NaiveTime(chrono::NaiveTime),
}
pub trait IntoBind {
fn into_bind(self) -> Value;
}
macro_rules! impl_into_bind_i64 {
($($t:ty),* $(,)?) => {
$(
impl IntoBind for $t {
fn into_bind(self) -> Value {
Value::I64(self as i64)
}
}
)*
};
}
impl_into_bind_i64!(i8, i16, i32, i64, u8, u16, u32);
impl_into_bind_i64!(u64, usize, isize);
impl IntoBind for f32 {
fn into_bind(self) -> Value {
Value::F64(self as f64)
}
}
impl IntoBind for f64 {
fn into_bind(self) -> Value {
Value::F64(self)
}
}
impl IntoBind for bool {
fn into_bind(self) -> Value {
Value::Bool(self)
}
}
impl IntoBind for &str {
fn into_bind(self) -> Value {
Value::Text(self.to_owned())
}
}
impl IntoBind for String {
fn into_bind(self) -> Value {
Value::Text(self)
}
}
impl IntoBind for &String {
fn into_bind(self) -> Value {
Value::Text(self.clone())
}
}
impl IntoBind for Vec<u8> {
fn into_bind(self) -> Value {
Value::Bytes(self)
}
}
impl IntoBind for &[u8] {
fn into_bind(self) -> Value {
Value::Bytes(self.to_vec())
}
}
impl IntoBind for Value {
fn into_bind(self) -> Value {
self
}
}
impl<T: IntoBind> IntoBind for Option<T> {
fn into_bind(self) -> Value {
match self {
None => Value::Null,
Some(inner) => inner.into_bind(),
}
}
}
#[cfg(feature = "json")]
impl IntoBind for serde_json::Value {
fn into_bind(self) -> Value {
Value::Json(self)
}
}
#[cfg(feature = "uuid")]
impl IntoBind for uuid::Uuid {
fn into_bind(self) -> Value {
Value::Uuid(self)
}
}
#[cfg(feature = "chrono")]
impl IntoBind for chrono::DateTime<chrono::Utc> {
fn into_bind(self) -> Value {
Value::DateTimeUtc(self)
}
}
#[cfg(feature = "chrono")]
impl IntoBind for chrono::NaiveDateTime {
fn into_bind(self) -> Value {
Value::NaiveDateTime(self)
}
}
#[cfg(feature = "chrono")]
impl IntoBind for chrono::NaiveDate {
fn into_bind(self) -> Value {
Value::NaiveDate(self)
}
}
#[cfg(feature = "chrono")]
impl IntoBind for chrono::NaiveTime {
fn into_bind(self) -> Value {
Value::NaiveTime(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn integers_become_i64() {
assert_eq!(7i8.into_bind(), Value::I64(7));
assert_eq!(7i16.into_bind(), Value::I64(7));
assert_eq!(7i32.into_bind(), Value::I64(7));
assert_eq!(7i64.into_bind(), Value::I64(7));
assert_eq!(7u8.into_bind(), Value::I64(7));
assert_eq!(7u16.into_bind(), Value::I64(7));
assert_eq!(7u32.into_bind(), Value::I64(7));
assert_eq!(7u64.into_bind(), Value::I64(7));
assert_eq!(7usize.into_bind(), Value::I64(7));
assert_eq!(7isize.into_bind(), Value::I64(7));
}
#[test]
fn u64_above_i64_max_wraps_intentionally() {
assert_eq!(((i64::MAX as u64) + 1).into_bind(), Value::I64(i64::MIN));
assert_eq!(u64::MAX.into_bind(), Value::I64(-1));
}
#[test]
fn floats_become_f64() {
assert_eq!(1.5f32.into_bind(), Value::F64(1.5));
assert_eq!(1.5f64.into_bind(), Value::F64(1.5));
}
#[test]
fn bool_becomes_bool() {
assert_eq!(true.into_bind(), Value::Bool(true));
assert_eq!(false.into_bind(), Value::Bool(false));
}
#[test]
fn strings_become_text() {
assert_eq!("hi".into_bind(), Value::Text("hi".to_string()));
assert_eq!(
String::from("hi").into_bind(),
Value::Text("hi".to_string())
);
let owned = String::from("hi");
assert_eq!((&owned).into_bind(), Value::Text("hi".to_string()));
}
#[test]
fn bytes_become_bytes() {
assert_eq!(vec![1u8, 2, 3].into_bind(), Value::Bytes(vec![1, 2, 3]));
let slice: &[u8] = &[1, 2, 3];
assert_eq!(slice.into_bind(), Value::Bytes(vec![1, 2, 3]));
}
#[test]
fn option_none_becomes_null() {
assert_eq!(Option::<i64>::None.into_bind(), Value::Null);
}
#[test]
fn option_some_becomes_inner() {
assert_eq!(Some(5i64).into_bind(), Value::I64(5));
}
#[test]
fn value_into_bind_is_identity() {
assert_eq!(Value::I64(1).into_bind(), Value::I64(1));
}
}