use crate::error::Result;
use crate::value::Value;
pub trait FromValue: Sized {
fn from_value(value: &Value) -> Result<Self>;
fn from_value_owned(value: Value) -> Result<Self> {
Self::from_value(&value)
}
}
impl FromValue for i64 {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::I64(v) => Ok(*v),
Value::Null => Err(crate::Error::TypeError("NULL value for i64".to_string())),
_ => Err(crate::Error::TypeError(format!(
"expected i64, got {:?}",
value
))),
}
}
}
impl FromValue for i32 {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::I32(v) => Ok(*v),
Value::I64(v) => {
(*v).try_into().map_err(|_| {
crate::Error::TypeError(format!("i64 value {} doesn't fit in i32", v))
})
}
Value::Null => Err(crate::Error::TypeError("NULL value for i32".to_string())),
_ => Err(crate::Error::TypeError(format!(
"expected i32, got {:?}",
value
))),
}
}
}
impl FromValue for String {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::String(v) => Ok(v.clone()),
Value::Null => Err(crate::Error::TypeError("NULL value for String".to_string())),
_ => Err(crate::Error::TypeError(format!(
"expected String, got {:?}",
value
))),
}
}
fn from_value_owned(value: Value) -> Result<Self> {
match value {
Value::String(v) => Ok(v),
Value::Null => Err(crate::Error::TypeError("NULL value for String".to_string())),
other => Err(crate::Error::TypeError(format!(
"expected String, got {:?}",
other
))),
}
}
}
impl FromValue for bool {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::Bool(v) => Ok(*v),
Value::Null => Err(crate::Error::TypeError("NULL value for bool".to_string())),
_ => Err(crate::Error::TypeError(format!(
"expected bool, got {:?}",
value
))),
}
}
}
impl FromValue for f64 {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::F64(v) => Ok(*v),
Value::Null => Err(crate::Error::TypeError("NULL value for f64".to_string())),
_ => Err(crate::Error::TypeError(format!(
"expected f64, got {:?}",
value
))),
}
}
}
impl FromValue for rust_decimal::Decimal {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::Decimal(v) => Ok(*v),
Value::Null => Err(crate::Error::TypeError(
"NULL value for Decimal".to_string(),
)),
_ => Err(crate::Error::TypeError(format!(
"expected Decimal, got {:?}",
value
))),
}
}
}
impl FromValue for chrono::NaiveDateTime {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::DateTime(v) => Ok(*v),
Value::Null => Err(crate::Error::TypeError(
"NULL value for DateTime".to_string(),
)),
_ => Err(crate::Error::TypeError(format!(
"expected DateTime, got {:?}",
value
))),
}
}
}
impl FromValue for uuid::Uuid {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::Uuid(v) => Ok(*v),
Value::Null => Err(crate::Error::TypeError("NULL value for Uuid".to_string())),
_ => Err(crate::Error::TypeError(format!(
"expected Uuid, got {:?}",
value
))),
}
}
}
impl FromValue for serde_json::Value {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::Json(v) => Ok(v.clone()),
Value::Null => Err(crate::Error::TypeError("NULL value for Json".to_string())),
_ => Err(crate::Error::TypeError(format!(
"expected Json, got {:?}",
value
))),
}
}
fn from_value_owned(value: Value) -> Result<Self> {
match value {
Value::Json(v) => Ok(v),
Value::Null => Err(crate::Error::TypeError("NULL value for Json".to_string())),
other => Err(crate::Error::TypeError(format!(
"expected Json, got {:?}",
other
))),
}
}
}
impl FromValue for Vec<u8> {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::Bytes(v) => Ok(v.clone()),
Value::Null => Err(crate::Error::TypeError("NULL value for Bytes".to_string())),
_ => Err(crate::Error::TypeError(format!(
"expected Bytes, got {:?}",
value
))),
}
}
fn from_value_owned(value: Value) -> Result<Self> {
match value {
Value::Bytes(v) => Ok(v),
Value::Null => Err(crate::Error::TypeError("NULL value for Bytes".to_string())),
other => Err(crate::Error::TypeError(format!(
"expected Bytes, got {:?}",
other
))),
}
}
}
impl<T: FromValue> FromValue for Option<T> {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::Null => Ok(None),
_ => T::from_value(value).map(Some),
}
}
fn from_value_owned(value: Value) -> Result<Self> {
match value {
Value::Null => Ok(None),
_ => T::from_value_owned(value).map(Some),
}
}
}
macro_rules! impl_vec_from_value {
($T:ty) => {
impl FromValue for Vec<$T> {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::Array(items) => items.iter().map(<$T>::from_value).collect(),
Value::Json(json_value) => decode_json_array(json_value, <$T>::from_value),
Value::Null => Err(crate::Error::TypeError(
concat!("NULL value for Vec<", stringify!($T), ">").to_string(),
)),
_ => Err(crate::Error::TypeError(format!(
concat!(
"expected Array or Json for Vec<",
stringify!($T),
">, got {:?}"
),
value
))),
}
}
}
impl FromValue for Vec<Vec<$T>> {
fn from_value(value: &Value) -> Result<Self> {
match value {
Value::Array2D(rows) => rows
.iter()
.map(|row| row.iter().map(<$T>::from_value).collect())
.collect(),
Value::Json(json_value) => decode_json_2d_array(json_value, <$T>::from_value),
Value::Null => Err(crate::Error::TypeError(
concat!("NULL value for Vec<Vec<", stringify!($T), ">>").to_string(),
)),
_ => Err(crate::Error::TypeError(format!(
concat!(
"expected Array2D or Json for Vec<Vec<",
stringify!($T),
">>, got {:?}"
),
value
))),
}
}
}
};
}
impl_vec_from_value!(String);
impl_vec_from_value!(i32);
impl_vec_from_value!(i64);
impl_vec_from_value!(f64);
impl_vec_from_value!(bool);
fn decode_json_array<T, F>(json_value: &serde_json::Value, decoder: F) -> Result<Vec<T>>
where
F: Fn(&Value) -> Result<T>,
{
if let serde_json::Value::Array(arr) = json_value {
let mut result = Vec::with_capacity(arr.len());
for json_item in arr {
let value = crate::value::json_to_value_ref(json_item);
result.push(decoder(&value)?);
}
Ok(result)
} else {
Err(crate::Error::TypeError(format!(
"expected JSON array, got {:?}",
json_value
)))
}
}
fn decode_json_2d_array<T, F>(json_value: &serde_json::Value, decoder: F) -> Result<Vec<Vec<T>>>
where
F: Fn(&Value) -> Result<T>,
{
if let serde_json::Value::Array(outer_arr) = json_value {
let mut result = Vec::with_capacity(outer_arr.len());
for json_row in outer_arr {
if let serde_json::Value::Array(inner_arr) = json_row {
let mut row = Vec::with_capacity(inner_arr.len());
for json_item in inner_arr {
let value = crate::value::json_to_value_ref(json_item);
row.push(decoder(&value)?);
}
result.push(row);
} else {
return Err(crate::Error::TypeError(format!(
"expected inner JSON array, got {:?}",
json_row
)));
}
}
Ok(result)
} else {
Err(crate::Error::TypeError(format!(
"expected JSON 2D array, got {:?}",
json_value
)))
}
}