use crate::error::ActiveStorageError;
pub type DValue = serde_json::Number;
fn as_i64(value: &DValue) -> Result<i64, ActiveStorageError> {
value
.as_i64()
.ok_or(ActiveStorageError::IncompatibleMissing(value.clone()))
}
fn as_u64(value: &DValue) -> Result<u64, ActiveStorageError> {
value
.as_u64()
.ok_or(ActiveStorageError::IncompatibleMissing(value.clone()))
}
fn as_f64(value: &DValue) -> Result<f64, ActiveStorageError> {
value
.as_f64()
.ok_or(ActiveStorageError::IncompatibleMissing(value.clone()))
}
pub trait TryFromDValue: Sized {
fn try_from_dvalue(value: DValue) -> Result<Self, ActiveStorageError>;
}
impl TryFromDValue for i32 {
fn try_from_dvalue(value: DValue) -> Result<Self, ActiveStorageError> {
Self::try_from(as_i64(&value)?).map_err(|_| ActiveStorageError::IncompatibleMissing(value))
}
}
impl TryFromDValue for i64 {
fn try_from_dvalue(value: DValue) -> Result<Self, ActiveStorageError> {
as_i64(&value)
}
}
impl TryFromDValue for u32 {
fn try_from_dvalue(value: DValue) -> Result<Self, ActiveStorageError> {
Self::try_from(as_u64(&value)?).map_err(|_| ActiveStorageError::IncompatibleMissing(value))
}
}
impl TryFromDValue for u64 {
fn try_from_dvalue(value: DValue) -> Result<Self, ActiveStorageError> {
as_u64(&value)
}
}
impl TryFromDValue for f32 {
fn try_from_dvalue(value: DValue) -> Result<Self, ActiveStorageError> {
let float = as_f64(&value)? as f32;
if float.is_finite() {
Ok(float)
} else {
Err(ActiveStorageError::IncompatibleMissing(value))
}
}
}
impl TryFromDValue for f64 {
fn try_from_dvalue(value: DValue) -> Result<Self, ActiveStorageError> {
as_f64(&value)
}
}
#[cfg(test)]
mod tests {
use num_traits::Float;
use super::*;
#[test]
fn test_dvalue_is_finite() {
assert!(DValue::from_f64(f64::infinity()).is_none());
}
#[test]
fn test_dvalue_is_not_nan() {
assert!(DValue::from_f64(f64::nan()).is_none());
}
#[test]
fn test_try_from_dvalue_i32() {
let result = i32::try_from_dvalue(42.into()).unwrap();
assert_eq!(42, result);
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(2147483648))")]
fn test_try_from_dvalue_i32_too_large() {
i32::try_from_dvalue((i32::MAX as i64 + 1).into()).unwrap();
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(-2147483649))")]
fn test_try_from_dvalue_i32_too_negative() {
i32::try_from_dvalue((i32::MIN as i64 - 1).into()).unwrap();
}
#[test]
fn test_try_from_dvalue_i64() {
let result = i64::try_from_dvalue((-42).into()).unwrap();
assert_eq!(-42, result);
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(9223372036854775808))")]
fn test_try_from_dvalue_i64_too_large() {
i64::try_from_dvalue((i64::MAX as u64 + 1).into()).unwrap();
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(1.0))")]
fn test_try_from_dvalue_i64_float() {
i64::try_from_dvalue(DValue::from_f64(1.0).unwrap()).unwrap();
}
#[test]
fn test_try_from_dvalue_u32() {
let result = u32::try_from_dvalue(42.into()).unwrap();
assert_eq!(42, result);
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(4294967296))")]
fn test_try_from_dvalue_u32_too_large() {
u32::try_from_dvalue((u32::MAX as u64 + 1).into()).unwrap();
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(-1))")]
fn test_try_from_dvalue_u32_negative() {
u32::try_from_dvalue((-1).into()).unwrap();
}
#[test]
fn test_try_from_dvalue_u64() {
let result = u64::try_from_dvalue(42.into()).unwrap();
assert_eq!(42, result);
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(-1))")]
fn test_try_from_dvalue_u64_negative() {
u64::try_from_dvalue((-1).into()).unwrap();
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(-1.0))")]
fn test_try_from_dvalue_u64_float() {
u64::try_from_dvalue(DValue::from_f64(-1.0).unwrap()).unwrap();
}
#[test]
fn test_try_from_dvalue_f32() {
let result = f32::try_from_dvalue(DValue::from_f64(42.0).unwrap()).unwrap();
assert_eq!(42.0, result);
}
#[test]
fn test_try_from_dvalue_f32_int() {
let result = f32::try_from_dvalue(42_u64.into()).unwrap();
assert_eq!(42.0, result);
}
#[test]
#[should_panic(expected = "IncompatibleMissing(Number(6.805646932770577e+38))")]
fn test_try_from_dvalue_f32_too_large() {
f32::try_from_dvalue(DValue::from_f64((f32::MAX as f64) * 2.0).unwrap()).unwrap();
}
#[test]
fn test_try_from_dvalue_f64() {
let result = f64::try_from_dvalue(DValue::from_f64(-42.0).unwrap()).unwrap();
assert_eq!(-42.0, result);
}
#[test]
fn test_try_from_dvalue_f64_int() {
let result = f64::try_from_dvalue(42_u64.into()).unwrap();
assert_eq!(42.0, result);
}
}