use bigdecimal::BigDecimal;
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
use num_bigint::BigInt;
use num_traits::ToPrimitive;
use serde::{Deserialize, Serialize};
use qubit_common::lang::DataType;
use super::error::{ValueError, ValueResult};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Value {
Empty(DataType),
Bool(bool),
Char(char),
Int8(i8),
Int16(i16),
Int32(i32),
Int64(i64),
Int128(i128),
UInt8(u8),
UInt16(u16),
UInt32(u32),
UInt64(u64),
UInt128(u128),
Float32(f32),
Float64(f64),
String(String),
Date(NaiveDate),
Time(NaiveTime),
DateTime(NaiveDateTime),
Instant(DateTime<Utc>),
BigInteger(BigInt),
BigDecimal(BigDecimal),
}
macro_rules! impl_get_value {
($(#[$attr:meta])* copy: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
$(#[$attr])*
pub fn $method(&self) -> ValueResult<$type> {
match self {
Value::$variant(v) => Ok(*v),
Value::Empty(_) => Err(ValueError::NoValue),
_ => Err(ValueError::TypeMismatch {
expected: $data_type,
actual: self.data_type(),
}),
}
}
};
($(#[$attr:meta])* ref: $method:ident, $variant:ident, $ret_type:ty, $data_type:expr, $conversion:expr) => {
$(#[$attr])*
pub fn $method(&self) -> ValueResult<$ret_type> {
match self {
Value::$variant(v) => {
let conv_fn: fn(&_) -> $ret_type = $conversion;
Ok(conv_fn(v))
},
Value::Empty(_) => Err(ValueError::NoValue),
_ => Err(ValueError::TypeMismatch {
expected: $data_type,
actual: self.data_type(),
}),
}
}
};
}
macro_rules! impl_set_value {
($(#[$attr:meta])* copy: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
$(#[$attr])*
pub fn $method(&mut self, value: $type) -> ValueResult<()> {
*self = Value::$variant(value);
Ok(())
}
};
($(#[$attr:meta])* owned: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
$(#[$attr])*
pub fn $method(&mut self, value: $type) -> ValueResult<()> {
*self = Value::$variant(value);
Ok(())
}
};
}
impl Value {
pub fn new<T>(value: T) -> Self
where
Self: ValueConstructor<T>,
{
<Self as ValueConstructor<T>>::from_type(value)
}
pub fn get<T>(&self) -> ValueResult<T>
where
Self: ValueGetter<T>,
{
<Self as ValueGetter<T>>::get_value(self)
}
pub fn set<T>(&mut self, value: T) -> ValueResult<()>
where
Self: ValueSetter<T>,
{
<Self as ValueSetter<T>>::set_value(self, value)
}
pub fn data_type(&self) -> DataType {
match self {
Value::Empty(dt) => *dt,
Value::Bool(_) => DataType::Bool,
Value::Char(_) => DataType::Char,
Value::Int8(_) => DataType::Int8,
Value::Int16(_) => DataType::Int16,
Value::Int32(_) => DataType::Int32,
Value::Int64(_) => DataType::Int64,
Value::Int128(_) => DataType::Int128,
Value::UInt8(_) => DataType::UInt8,
Value::UInt16(_) => DataType::UInt16,
Value::UInt32(_) => DataType::UInt32,
Value::UInt64(_) => DataType::UInt64,
Value::UInt128(_) => DataType::UInt128,
Value::Float32(_) => DataType::Float32,
Value::Float64(_) => DataType::Float64,
Value::String(_) => DataType::String,
Value::Date(_) => DataType::Date,
Value::Time(_) => DataType::Time,
Value::DateTime(_) => DataType::DateTime,
Value::Instant(_) => DataType::Instant,
Value::BigInteger(_) => DataType::BigInteger,
Value::BigDecimal(_) => DataType::BigDecimal,
}
}
pub fn is_empty(&self) -> bool {
matches!(self, Value::Empty(_))
}
pub fn clear(&mut self) {
let dt = self.data_type();
*self = Value::Empty(dt);
}
pub fn set_type(&mut self, data_type: DataType) {
if self.data_type() != data_type {
*self = Value::Empty(data_type);
}
}
impl_get_value! {
copy: get_bool, Bool, bool, DataType::Bool
}
impl_get_value! {
copy: get_char, Char, char, DataType::Char
}
impl_get_value! {
copy: get_int8, Int8, i8, DataType::Int8
}
impl_get_value! {
copy: get_int16, Int16, i16, DataType::Int16
}
impl_get_value! {
copy: get_int32, Int32, i32, DataType::Int32
}
impl_get_value! {
copy: get_int64, Int64, i64, DataType::Int64
}
impl_get_value! {
copy: get_int128, Int128, i128, DataType::Int128
}
impl_get_value! {
copy: get_uint8, UInt8, u8, DataType::UInt8
}
impl_get_value! {
copy: get_uint16, UInt16, u16, DataType::UInt16
}
impl_get_value! {
copy: get_uint32, UInt32, u32, DataType::UInt32
}
impl_get_value! {
copy: get_uint64, UInt64, u64, DataType::UInt64
}
impl_get_value! {
copy: get_uint128, UInt128, u128, DataType::UInt128
}
impl_get_value! {
copy: get_float32, Float32, f32, DataType::Float32
}
impl_get_value! {
copy: get_float64, Float64, f64, DataType::Float64
}
impl_get_value! {
ref: get_string, String, &str, DataType::String, |s: &String| s.as_str()
}
impl_get_value! {
copy: get_date, Date, NaiveDate, DataType::Date
}
impl_get_value! {
copy: get_time, Time, NaiveTime, DataType::Time
}
impl_get_value! {
copy: get_datetime, DateTime, NaiveDateTime, DataType::DateTime
}
impl_get_value! {
copy: get_instant, Instant, DateTime<Utc>, DataType::Instant
}
impl_get_value! {
ref: get_biginteger, BigInteger, BigInt, DataType::BigInteger, |v: &BigInt| v.clone()
}
impl_get_value! {
ref: get_bigdecimal, BigDecimal, BigDecimal, DataType::BigDecimal, |v: &BigDecimal| v.clone()
}
pub fn as_bool(&self) -> ValueResult<bool> {
match self {
Value::Bool(v) => Ok(*v),
Value::Int8(v) => Ok(*v != 0),
Value::Int16(v) => Ok(*v != 0),
Value::Int32(v) => Ok(*v != 0),
Value::Int64(v) => Ok(*v != 0),
Value::Int128(v) => Ok(*v != 0),
Value::UInt8(v) => Ok(*v != 0),
Value::UInt16(v) => Ok(*v != 0),
Value::UInt32(v) => Ok(*v != 0),
Value::UInt64(v) => Ok(*v != 0),
Value::UInt128(v) => Ok(*v != 0),
Value::String(s) => s.parse::<bool>().map_err(|_| {
ValueError::ConversionError(format!("Cannot convert '{}' to boolean", s))
}),
Value::Empty(_) => Err(ValueError::NoValue),
_ => Err(ValueError::ConversionFailed {
from: self.data_type(),
to: DataType::Bool,
}),
}
}
pub fn as_int32(&self) -> ValueResult<i32> {
match self {
Value::Int32(v) => Ok(*v),
Value::Bool(v) => Ok(if *v { 1 } else { 0 }),
Value::Char(v) => Ok(*v as i32),
Value::Int8(v) => Ok(*v as i32),
Value::Int16(v) => Ok(*v as i32),
Value::Int64(v) => (*v)
.try_into()
.map_err(|_| ValueError::ConversionError("i64 value out of i32 range".to_string())),
Value::Int128(v) => (*v).try_into().map_err(|_| {
ValueError::ConversionError("i128 value out of i32 range".to_string())
}),
Value::UInt8(v) => Ok(*v as i32),
Value::UInt16(v) => Ok(*v as i32),
Value::UInt32(v) => (*v)
.try_into()
.map_err(|_| ValueError::ConversionError("u32 value out of i32 range".to_string())),
Value::UInt64(v) => (*v)
.try_into()
.map_err(|_| ValueError::ConversionError("u64 value out of i32 range".to_string())),
Value::UInt128(v) => (*v).try_into().map_err(|_| {
ValueError::ConversionError("u128 value out of i32 range".to_string())
}),
Value::Float32(v) => Ok(*v as i32),
Value::Float64(v) => Ok(*v as i32),
Value::String(s) => s
.parse::<i32>()
.map_err(|_| ValueError::ConversionError(format!("Cannot convert '{}' to i32", s))),
Value::Empty(_) => Err(ValueError::NoValue),
Value::BigInteger(v) => v.to_i32().ok_or_else(|| {
ValueError::ConversionError("BigInteger value out of i32 range".to_string())
}),
Value::BigDecimal(v) => v.to_i32().ok_or_else(|| {
ValueError::ConversionError(
"BigDecimal value cannot be converted to i32".to_string(),
)
}),
_ => Err(ValueError::ConversionFailed {
from: self.data_type(),
to: DataType::Int32,
}),
}
}
pub fn as_int64(&self) -> ValueResult<i64> {
match self {
Value::Int64(v) => Ok(*v),
Value::Bool(v) => Ok(if *v { 1 } else { 0 }),
Value::Char(v) => Ok(*v as i64),
Value::Int8(v) => Ok(*v as i64),
Value::Int16(v) => Ok(*v as i64),
Value::Int32(v) => Ok(*v as i64),
Value::Int128(v) => (*v).try_into().map_err(|_| {
ValueError::ConversionError("i128 value out of i64 range".to_string())
}),
Value::UInt8(v) => Ok(*v as i64),
Value::UInt16(v) => Ok(*v as i64),
Value::UInt32(v) => Ok(*v as i64),
Value::UInt64(v) => (*v)
.try_into()
.map_err(|_| ValueError::ConversionError("u64 value out of i64 range".to_string())),
Value::UInt128(v) => (*v).try_into().map_err(|_| {
ValueError::ConversionError("u128 value out of i64 range".to_string())
}),
Value::Float32(v) => Ok(*v as i64),
Value::Float64(v) => Ok(*v as i64),
Value::String(s) => s
.parse::<i64>()
.map_err(|_| ValueError::ConversionError(format!("Cannot convert '{}' to i64", s))),
Value::Empty(_) => Err(ValueError::NoValue),
Value::BigInteger(v) => v.to_i64().ok_or_else(|| {
ValueError::ConversionError("BigInteger value out of i64 range".to_string())
}),
Value::BigDecimal(v) => v.to_i64().ok_or_else(|| {
ValueError::ConversionError(
"BigDecimal value cannot be converted to i64".to_string(),
)
}),
_ => Err(ValueError::ConversionFailed {
from: self.data_type(),
to: DataType::Int64,
}),
}
}
pub fn as_float64(&self) -> ValueResult<f64> {
match self {
Value::Float64(v) => Ok(*v),
Value::Bool(v) => Ok(if *v { 1.0 } else { 0.0 }),
Value::Char(v) => Ok(*v as u32 as f64),
Value::Float32(v) => Ok(*v as f64),
Value::Int8(v) => Ok(*v as f64),
Value::Int16(v) => Ok(*v as f64),
Value::Int32(v) => Ok(*v as f64),
Value::Int64(v) => Ok(*v as f64),
Value::Int128(v) => Ok(*v as f64),
Value::UInt8(v) => Ok(*v as f64),
Value::UInt16(v) => Ok(*v as f64),
Value::UInt32(v) => Ok(*v as f64),
Value::UInt64(v) => Ok(*v as f64),
Value::UInt128(v) => Ok(*v as f64),
Value::String(s) => s
.parse::<f64>()
.map_err(|_| ValueError::ConversionError(format!("Cannot convert '{}' to f64", s))),
Value::Empty(_) => Err(ValueError::NoValue),
Value::BigInteger(v) => v.to_f64().ok_or_else(|| {
ValueError::ConversionError(
"BigInteger value cannot be converted to f64".to_string(),
)
}),
Value::BigDecimal(v) => v.to_f64().ok_or_else(|| {
ValueError::ConversionError(
"BigDecimal value cannot be converted to f64".to_string(),
)
}),
_ => Err(ValueError::ConversionFailed {
from: self.data_type(),
to: DataType::Float64,
}),
}
}
pub fn as_string(&self) -> ValueResult<String> {
match self {
Value::String(v) => Ok(v.clone()),
Value::Bool(v) => Ok(v.to_string()),
Value::Char(v) => Ok(v.to_string()),
Value::Int8(v) => Ok(v.to_string()),
Value::Int16(v) => Ok(v.to_string()),
Value::Int32(v) => Ok(v.to_string()),
Value::Int64(v) => Ok(v.to_string()),
Value::Int128(v) => Ok(v.to_string()),
Value::UInt8(v) => Ok(v.to_string()),
Value::UInt16(v) => Ok(v.to_string()),
Value::UInt32(v) => Ok(v.to_string()),
Value::UInt64(v) => Ok(v.to_string()),
Value::UInt128(v) => Ok(v.to_string()),
Value::Float32(v) => Ok(v.to_string()),
Value::Float64(v) => Ok(v.to_string()),
Value::Date(v) => Ok(v.to_string()),
Value::Time(v) => Ok(v.to_string()),
Value::DateTime(v) => Ok(v.to_string()),
Value::Instant(v) => Ok(v.to_rfc3339()),
Value::BigInteger(v) => Ok(v.to_string()),
Value::BigDecimal(v) => Ok(v.to_string()),
Value::Empty(_) => Err(ValueError::NoValue),
}
}
impl_set_value! {
copy: set_bool, Bool, bool, DataType::Bool
}
impl_set_value! {
copy: set_char, Char, char, DataType::Char
}
impl_set_value! {
copy: set_int8, Int8, i8, DataType::Int8
}
impl_set_value! {
copy: set_int16, Int16, i16, DataType::Int16
}
impl_set_value! {
copy: set_int32, Int32, i32, DataType::Int32
}
impl_set_value! {
copy: set_int64, Int64, i64, DataType::Int64
}
impl_set_value! {
copy: set_int128, Int128, i128, DataType::Int128
}
impl_set_value! {
copy: set_uint8, UInt8, u8, DataType::UInt8
}
impl_set_value! {
copy: set_uint16, UInt16, u16, DataType::UInt16
}
impl_set_value! {
copy: set_uint32, UInt32, u32, DataType::UInt32
}
impl_set_value! {
copy: set_uint64, UInt64, u64, DataType::UInt64
}
impl_set_value! {
copy: set_uint128, UInt128, u128, DataType::UInt128
}
impl_set_value! {
copy: set_float32, Float32, f32, DataType::Float32
}
impl_set_value! {
copy: set_float64, Float64, f64, DataType::Float64
}
impl_set_value! {
owned: set_string, String, String, DataType::String
}
impl_set_value! {
copy: set_date, Date, NaiveDate, DataType::Date
}
impl_set_value! {
copy: set_time, Time, NaiveTime, DataType::Time
}
impl_set_value! {
copy: set_datetime, DateTime, NaiveDateTime, DataType::DateTime
}
impl_set_value! {
copy: set_instant, Instant, DateTime<Utc>, DataType::Instant
}
impl_set_value! {
owned: set_biginteger, BigInteger, BigInt, DataType::BigInteger
}
impl_set_value! {
owned: set_bigdecimal, BigDecimal, BigDecimal, DataType::BigDecimal
}
}
impl Default for Value {
fn default() -> Self {
Value::Empty(DataType::String)
}
}
#[doc(hidden)]
pub trait ValueGetter<T> {
fn get_value(&self) -> ValueResult<T>;
}
#[doc(hidden)]
pub trait ValueConstructor<T> {
fn from_type(value: T) -> Self;
}
#[doc(hidden)]
pub trait ValueSetter<T> {
fn set_value(&mut self, value: T) -> ValueResult<()>;
}
macro_rules! impl_value_traits {
($type:ty, $variant:ident, $get_method:ident, $set_method:ident) => {
impl ValueGetter<$type> for Value {
fn get_value(&self) -> ValueResult<$type> {
self.$get_method()
}
}
impl ValueSetter<$type> for Value {
fn set_value(&mut self, value: $type) -> ValueResult<()> {
self.$set_method(value)
}
}
impl ValueConstructor<$type> for Value {
fn from_type(value: $type) -> Self {
Value::$variant(value)
}
}
};
}
impl_value_traits!(bool, Bool, get_bool, set_bool);
impl_value_traits!(char, Char, get_char, set_char);
impl_value_traits!(i8, Int8, get_int8, set_int8);
impl_value_traits!(i16, Int16, get_int16, set_int16);
impl_value_traits!(i32, Int32, get_int32, set_int32);
impl_value_traits!(i64, Int64, get_int64, set_int64);
impl_value_traits!(i128, Int128, get_int128, set_int128);
impl_value_traits!(u8, UInt8, get_uint8, set_uint8);
impl_value_traits!(u16, UInt16, get_uint16, set_uint16);
impl_value_traits!(u32, UInt32, get_uint32, set_uint32);
impl_value_traits!(u64, UInt64, get_uint64, set_uint64);
impl_value_traits!(u128, UInt128, get_uint128, set_uint128);
impl_value_traits!(f32, Float32, get_float32, set_float32);
impl_value_traits!(f64, Float64, get_float64, set_float64);
impl_value_traits!(NaiveDate, Date, get_date, set_date);
impl_value_traits!(NaiveTime, Time, get_time, set_time);
impl_value_traits!(NaiveDateTime, DateTime, get_datetime, set_datetime);
impl_value_traits!(DateTime<Utc>, Instant, get_instant, set_instant);
impl_value_traits!(BigInt, BigInteger, get_biginteger, set_biginteger);
impl_value_traits!(BigDecimal, BigDecimal, get_bigdecimal, set_bigdecimal);
impl ValueGetter<String> for Value {
fn get_value(&self) -> ValueResult<String> {
self.get_string().map(|s| s.to_string())
}
}
impl ValueSetter<String> for Value {
fn set_value(&mut self, value: String) -> ValueResult<()> {
self.set_string(value)
}
}
impl ValueConstructor<String> for Value {
fn from_type(value: String) -> Self {
Value::String(value)
}
}
impl ValueSetter<&str> for Value {
fn set_value(&mut self, value: &str) -> ValueResult<()> {
self.set_string(value.to_string())
}
}
impl ValueConstructor<&str> for Value {
fn from_type(value: &str) -> Self {
Value::String(value.to_string())
}
}