1use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
4use rust_decimal::Decimal;
5use serde::Serialize;
6use uuid::Uuid;
7
8#[derive(Debug, Clone, PartialEq, Serialize)]
21#[serde(untagged)]
22pub enum Value {
23 Null,
25 Bool(bool),
27 Int(i64),
29 Float(f64),
31 Decimal(Decimal),
33 Text(String),
35 Bytes(Vec<u8>),
37 Uuid(Uuid),
39 Date(NaiveDate),
41 Time(NaiveTime),
43 Timestamp(DateTime<Utc>),
45 Json(serde_json::Value),
47}
48
49impl Value {
50 pub fn is_null(&self) -> bool {
52 matches!(self, Value::Null)
53 }
54
55 pub fn kind(&self) -> &'static str {
57 match self {
58 Value::Null => "null",
59 Value::Bool(_) => "bool",
60 Value::Int(_) => "int",
61 Value::Float(_) => "float",
62 Value::Decimal(_) => "decimal",
63 Value::Text(_) => "text",
64 Value::Bytes(_) => "bytes",
65 Value::Uuid(_) => "uuid",
66 Value::Date(_) => "date",
67 Value::Time(_) => "time",
68 Value::Timestamp(_) => "timestamp",
69 Value::Json(_) => "json",
70 }
71 }
72}
73
74macro_rules! impl_from {
75 ($($t:ty => $variant:ident $(as $cast:ty)?),* $(,)?) => {$(
76 impl From<$t> for Value {
77 fn from(v: $t) -> Self { Value::$variant(v $(as $cast)?) }
78 }
79 )*};
80}
81
82impl_from!(
83 bool => Bool,
84 i8 => Int as i64, i16 => Int as i64, i32 => Int as i64, i64 => Int,
85 u8 => Int as i64, u16 => Int as i64, u32 => Int as i64,
86 f32 => Float as f64, f64 => Float,
87 String => Text, Vec<u8> => Bytes, serde_json::Value => Json,
88 Decimal => Decimal, Uuid => Uuid, NaiveDate => Date, NaiveTime => Time,
89 DateTime<Utc> => Timestamp,
90);
91
92impl From<&str> for Value {
93 fn from(v: &str) -> Self {
94 Value::Text(v.to_owned())
95 }
96}
97
98impl<T: Into<Value>> From<Option<T>> for Value {
99 fn from(v: Option<T>) -> Self {
100 v.map_or(Value::Null, Into::into)
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn conversions() {
110 assert_eq!(Value::from(3_i32), Value::Int(3));
111 assert_eq!(Value::from("a"), Value::Text("a".into()));
112 assert_eq!(Value::from(None::<i64>), Value::Null);
113 assert_eq!(Value::from(Some(true)), Value::Bool(true));
114 assert_eq!(Value::from(Uuid::nil()).kind(), "uuid");
115 }
116}