use crate::{DataType, HighPrecisionDatetime};
#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
Null,
Bool(bool),
Int32(i32),
Int64(i64),
Float64(f64),
String(&'a str),
Date32(i32),
TimestampMicros(i64),
Time64Micros(i64),
Datetime(HighPrecisionDatetime),
Enum(&'a str),
Byte(u8),
}
#[derive(Debug, Clone, PartialEq)]
pub enum OwnedValue {
Null,
Bool(bool),
Int32(i32),
Int64(i64),
Float64(f64),
String(String),
Date32(i32),
TimestampMicros(i64),
Time64Micros(i64),
Datetime(HighPrecisionDatetime),
Enum(String),
Byte(u8),
}
impl<'a> Value<'a> {
#[inline]
pub fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
#[inline]
pub fn as_f64(&self) -> Option<f64> {
match self {
Self::Float64(v) => Some(*v),
Self::Int64(v) => Some(*v as f64),
Self::Int32(v) => Some(*v as f64),
Self::Bool(v) => Some(if *v { 1.0 } else { 0.0 }),
Self::Byte(v) => Some(*v as f64),
_ => None,
}
}
#[inline]
pub fn as_i64(&self) -> Option<i64> {
match self {
Self::Int64(v) => Some(*v),
Self::Int32(v) => Some(*v as i64),
Self::Bool(v) => Some(if *v { 1 } else { 0 }),
Self::Byte(v) => Some(*v as i64),
Self::Date32(v) => Some(*v as i64),
Self::TimestampMicros(v) => Some(*v),
Self::Time64Micros(v) => Some(*v),
Self::Float64(v)
if v.is_finite()
&& v.fract() == 0.0
&& *v >= i64::MIN as f64
&& *v <= i64::MAX as f64 =>
{
Some(*v as i64)
}
_ => None,
}
}
#[inline]
pub fn as_str(&self) -> Option<&'a str> {
match self {
Self::String(s) | Self::Enum(s) => Some(s),
_ => None,
}
}
#[inline]
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(v) => Some(*v),
Self::Int32(v) => Some(*v != 0),
Self::Int64(v) => Some(*v != 0),
_ => None,
}
}
#[inline]
pub fn to_owned(&self) -> OwnedValue {
match self {
Self::Null => OwnedValue::Null,
Self::Bool(v) => OwnedValue::Bool(*v),
Self::Int32(v) => OwnedValue::Int32(*v),
Self::Int64(v) => OwnedValue::Int64(*v),
Self::Float64(v) => OwnedValue::Float64(*v),
Self::String(s) => OwnedValue::String((*s).to_string()),
Self::Date32(v) => OwnedValue::Date32(*v),
Self::TimestampMicros(v) => OwnedValue::TimestampMicros(*v),
Self::Time64Micros(v) => OwnedValue::Time64Micros(*v),
Self::Datetime(dt) => OwnedValue::Datetime(*dt),
Self::Enum(s) => OwnedValue::Enum((*s).to_string()),
Self::Byte(v) => OwnedValue::Byte(*v),
}
}
#[inline]
pub fn datatype(&self) -> DataType {
match self {
Self::Null => DataType::String,
Self::Bool(_) => DataType::Bool,
Self::Int32(_) => DataType::Int32,
Self::Int64(_) => DataType::Int64,
Self::Float64(_) => DataType::Float64,
Self::String(_) => DataType::String,
Self::Date32(_) => DataType::Date,
Self::TimestampMicros(_) | Self::Datetime(_) => DataType::Datetime,
Self::Time64Micros(_) => DataType::Time,
Self::Enum(_) => DataType::Enumeration,
Self::Byte(_) => DataType::Byte,
}
}
}
impl OwnedValue {
#[inline]
pub fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
#[inline]
pub fn as_f64(&self) -> Option<f64> {
match self {
Self::Float64(v) => Some(*v),
Self::Int64(v) => Some(*v as f64),
Self::Int32(v) => Some(*v as f64),
Self::Bool(v) => Some(if *v { 1.0 } else { 0.0 }),
Self::Byte(v) => Some(*v as f64),
_ => None,
}
}
#[inline]
pub fn as_i64(&self) -> Option<i64> {
match self {
Self::Int64(v) => Some(*v),
Self::Int32(v) => Some(*v as i64),
Self::Bool(v) => Some(if *v { 1 } else { 0 }),
Self::Byte(v) => Some(*v as i64),
Self::Date32(v) => Some(*v as i64),
Self::TimestampMicros(v) => Some(*v),
Self::Time64Micros(v) => Some(*v),
Self::Float64(v)
if v.is_finite()
&& v.fract() == 0.0
&& *v >= i64::MIN as f64
&& *v <= i64::MAX as f64 =>
{
Some(*v as i64)
}
_ => None,
}
}
#[inline]
pub fn as_str(&self) -> Option<&str> {
match self {
Self::String(s) | Self::Enum(s) => Some(s),
_ => None,
}
}
#[inline]
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(v) => Some(*v),
Self::Int32(v) => Some(*v != 0),
Self::Int64(v) => Some(*v != 0),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_value_conversions() {
assert_eq!(Value::Float64(12.5).as_f64(), Some(12.5));
assert_eq!(Value::Int64(42).as_i64(), Some(42));
assert_eq!(Value::String("hello").as_str(), Some("hello"));
assert_eq!(Value::Bool(true).as_bool(), Some(true));
assert!(Value::Null.is_null());
}
#[test]
fn test_owned_value() {
let owned = Value::String("hello").to_owned();
assert_eq!(owned.as_str(), Some("hello"));
}
#[test]
fn test_datatype() {
assert_eq!(Value::Float64(0.0).datatype(), DataType::Float64);
assert_eq!(Value::Bool(false).datatype(), DataType::Bool);
assert_eq!(Value::Date32(0).datatype(), DataType::Date);
}
}