use super::{DataValue, Extract};
macro_rules! impl_extract_nums {
($($t:ty),*) => {
$(
impl Extract for $t {
#[inline]
fn extract(v: &DataValue) -> $t {
use DataValue::*;
match v {
Bool(b) => (if b == &true { 1 } else { 0 }) as $t,
U32(i) => *i as $t,
I32(i) => *i as $t,
U8(i) => *i as $t,
U64(i) => *i as $t,
I64(i) => *i as $t,
F32(i) => *i as $t,
F64(i) => *i as $t,
U128(i) => *i as $t,
I128(i) => *i as $t,
EnumNumber(i) => *i as $t,
_ => 0 as $t,
}
}
}
)*
};
}
impl_extract_nums!(u32, u64, i32, i64, f32, f64, u128, i128);
impl Extract for u8 {
fn extract(v: &DataValue) -> u8 {
use DataValue::*;
match v {
U8(i) => *i,
_ => 0,
}
}
}
impl Extract for bool {
fn extract(v: &DataValue) -> bool {
match v {
DataValue::Bool(i) => *i,
DataValue::U8(i) => *i != 0,
DataValue::U32(i) => *i != 0,
DataValue::I32(i) => *i != 0,
DataValue::U64(i) => *i != 0,
DataValue::I64(i) => *i != 0,
DataValue::F32(i) => *i != 0.,
DataValue::F64(i) => *i != 0.,
_ => false,
}
}
}
impl Extract for String {
fn extract(v: &DataValue) -> String {
match v {
DataValue::String(i) => i.to_string(),
v => format!("{v}"),
}
}
}
impl<T> Extract for Vec<T>
where
T: Extract,
{
fn extract(v: &DataValue) -> Vec<T> {
use DataValue::*;
match v {
Vec(i) => i.iter().map(|x| T::extract(x)).collect(),
_ => vec![],
}
}
}
impl<V> Extract for std::collections::HashMap<smartstring::alias::String, V>
where
V: Extract,
{
fn extract(v: &DataValue) -> std::collections::HashMap<smartstring::alias::String, V> {
use DataValue::*;
match v {
Map(i) => i.iter().map(|(k, v)| (k.clone(), V::extract(v))).collect(),
_ => Default::default(),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use rstest::*;
#[rstest]
#[case(DataValue::U8(1), 1)]
#[case(DataValue::U32(1), 1)]
#[case(DataValue::I32(1), 1)]
#[case(DataValue::U64(1), 1)]
#[case(DataValue::I64(1), 1)]
#[case(DataValue::F32(1.0), 1)]
#[case(DataValue::F64(1.0), 1)]
#[case(DataValue::U128(1), 1)]
#[case(DataValue::I128(1), 1)]
#[case(DataValue::EnumNumber(1), 1)]
#[case(DataValue::Bool(true), 1)]
#[case(DataValue::Bool(false), 0)]
#[case(DataValue::String("1".into()), 0)]
fn test_extract_num(#[case] input: DataValue, #[case] expected: u32) {
assert_eq!(u32::extract(&input), expected);
}
#[rstest]
#[case(DataValue::U8(1), "1")]
#[case(DataValue::U32(1), "1")]
#[case(DataValue::I32(1), "1")]
#[case(DataValue::U64(1), "1")]
#[case(DataValue::I64(1), "1")]
#[case(DataValue::F32(1.1), "1.1")]
#[case(DataValue::F64(1.1), "1.1")]
#[case(DataValue::U128(1), "1")]
#[case(DataValue::I128(1), "1")]
#[case(DataValue::EnumNumber(1), "1")]
#[case(DataValue::Bool(true), "true")]
#[case(DataValue::Bool(false), "false")]
#[case(DataValue::String("1".into()), "1")]
fn test_extract_string(#[case] input: DataValue, #[case] expected: &str) {
assert_eq!(String::extract(&input), expected.to_string());
}
#[rstest]
#[case(DataValue::U8(1), 1)]
#[case(DataValue::U32(1), 1)]
#[case(DataValue::I32(1), 1)]
#[case(DataValue::U64(1), 1)]
#[case(DataValue::I64(1), 1)]
#[case(DataValue::F32(1.0), 1)]
#[case(DataValue::F64(1.0), 1)]
#[case(DataValue::U128(1), 1)]
#[case(DataValue::I128(1), 1)]
#[case(DataValue::EnumNumber(1), 1)]
#[case(DataValue::Bool(true), 1)]
#[case(DataValue::Bool(false), 0)]
#[case(DataValue::String("1".into()), 0)]
fn test_extract_u64(#[case] input: DataValue, #[case] expected: u64) {
assert_eq!(u64::extract(&input), expected);
}
#[rstest]
#[case(DataValue::U8(1), 1)]
#[case(DataValue::U32(1), 1)]
#[case(DataValue::I32(1), 1)]
#[case(DataValue::U64(1), 1)]
#[case(DataValue::I64(1), 1)]
#[case(DataValue::F32(1.0), 1)]
#[case(DataValue::F64(1.0), 1)]
#[case(DataValue::U128(1), 1)]
#[case(DataValue::I128(1), 1)]
#[case(DataValue::EnumNumber(1), 1)]
#[case(DataValue::Bool(true), 1)]
#[case(DataValue::Bool(false), 0)]
#[case(DataValue::String("1".into()), 0)]
fn test_extract_i32(#[case] input: DataValue, #[case] expected: i32) {
assert_eq!(i32::extract(&input), expected);
}
#[rstest]
#[case(DataValue::U8(1), 1)]
#[case(DataValue::U32(1), 1)]
#[case(DataValue::I32(1), 1)]
#[case(DataValue::U64(1), 1)]
#[case(DataValue::I64(1), 1)]
#[case(DataValue::F32(1.0), 1)]
#[case(DataValue::F64(1.0), 1)]
#[case(DataValue::U128(1), 1)]
#[case(DataValue::I128(1), 1)]
#[case(DataValue::EnumNumber(1), 1)]
#[case(DataValue::Bool(true), 1)]
#[case(DataValue::Bool(false), 0)]
#[case(DataValue::String("1".into()), 0)]
fn test_extract_i64(#[case] input: DataValue, #[case] expected: i64) {
assert_eq!(i64::extract(&input), expected);
}
#[rstest]
#[case(DataValue::U8(1), 1f64)]
#[case(DataValue::U32(1), 1f64)]
#[case(DataValue::I32(1), 1f64)]
#[case(DataValue::U64(1), 1f64)]
#[case(DataValue::I64(1), 1f64)]
#[case(DataValue::F32(1.0), 1f64)]
#[case(DataValue::F64(1.0), 1f64)]
#[case(DataValue::U128(1), 1f64)]
#[case(DataValue::I128(1), 1f64)]
#[case(DataValue::EnumNumber(1), 1f64)]
#[case(DataValue::Bool(true), 1f64)]
#[case(DataValue::Bool(false), 0f64)]
#[case(DataValue::String("1".into()), 0f64)]
fn test_extract_f64(#[case] input: DataValue, #[case] expected: f64) {
assert_eq!(f64::extract(&input), expected);
}
#[rstest]
#[case(DataValue::U8(1), 1f32)]
#[case(DataValue::U32(1), 1f32)]
#[case(DataValue::I32(1), 1f32)]
#[case(DataValue::U64(1), 1f32)]
#[case(DataValue::I64(1), 1f32)]
#[case(DataValue::F32(1.0), 1f32)]
#[case(DataValue::F64(1.0), 1f32)]
#[case(DataValue::U128(1), 1f32)]
#[case(DataValue::I128(1), 1f32)]
#[case(DataValue::EnumNumber(1), 1f32)]
#[case(DataValue::Bool(true), 1f32)]
#[case(DataValue::Bool(false), 0f32)]
#[case(DataValue::String("1".into()), 0f32)]
#[case(DataValue::Null, 0f32)]
fn test_extract_f32(#[case] input: DataValue, #[case] expected: f32) {
assert_eq!(f32::extract(&input), expected);
}
#[rstest]
#[case(DataValue::Vec(vec![1.into()]), vec![1])]
#[case(DataValue::Vec(vec![1.into(), 2.into()]), vec![1, 2])]
#[case(DataValue::Vec(vec![1.into(), 2.into(), 3.into()]), vec![1, 2, 3])]
fn test_extract_vec(#[case] input: DataValue, #[case] expected: Vec<u32>) {
assert_eq!(Vec::<u32>::extract(&input), expected);
}
#[rstest]
#[case(DataValue::Map(crate::stdhashmap!("a" => 1)), crate::stdhashmap!("a" => 1))]
#[case(DataValue::Map(crate::stdhashmap!("a" => 1, "b" => 2)), crate::stdhashmap!("a" => 1, "b" => 2))]
#[case(DataValue::Map(crate::stdhashmap!("a" => 1, "b" => 2, "c" => 3)), crate::stdhashmap!("a" => 1, "b" => 2, "c" => 3))]
fn test_extract_map(
#[case] input: DataValue,
#[case] expected: std::collections::HashMap<smartstring::alias::String, i32>,
) {
assert_eq!(
std::collections::HashMap::<smartstring::alias::String, i32>::extract(&input),
expected
);
}
}