use std::collections::HashMap;
use super::DataValue;
impl From<()> for DataValue {
fn from(_value: ()) -> Self {
DataValue::Null
}
}
impl From<u32> for DataValue {
fn from(value: u32) -> Self {
DataValue::U32(value)
}
}
impl From<usize> for DataValue {
fn from(value: usize) -> Self {
DataValue::U32(value as u32)
}
}
impl From<i32> for DataValue {
fn from(value: i32) -> Self {
DataValue::I32(value)
}
}
impl From<u8> for DataValue {
fn from(value: u8) -> Self {
DataValue::U8(value)
}
}
impl From<u64> for DataValue {
fn from(value: u64) -> Self {
DataValue::U64(value)
}
}
impl From<i64> for DataValue {
fn from(value: i64) -> Self {
DataValue::I64(value)
}
}
impl From<f32> for DataValue {
fn from(value: f32) -> Self {
DataValue::F32(value)
}
}
impl From<u128> for DataValue {
fn from(value: u128) -> Self {
DataValue::U128(value)
}
}
impl From<i128> for DataValue {
fn from(value: i128) -> Self {
DataValue::I128(value)
}
}
impl From<f64> for DataValue {
fn from(value: f64) -> Self {
DataValue::F64(value)
}
}
impl From<String> for DataValue {
fn from(value: String) -> Self {
DataValue::String(value.into())
}
}
impl From<smartstring::alias::String> for DataValue {
fn from(value: smartstring::alias::String) -> Self {
DataValue::String(value)
}
}
impl From<&str> for DataValue {
fn from(value: &str) -> Self {
DataValue::String(value.into())
}
}
impl From<Vec<u8>> for DataValue {
fn from(value: Vec<u8>) -> Self {
DataValue::Bytes(value)
}
}
impl From<bool> for DataValue {
fn from(value: bool) -> Self {
DataValue::Bool(value)
}
}
impl From<Option<String>> for DataValue {
fn from(value: Option<String>) -> Self {
match value {
Some(value) => DataValue::String(value.into()),
None => DataValue::Null,
}
}
}
impl From<Option<smartstring::alias::String>> for DataValue {
fn from(value: Option<smartstring::alias::String>) -> Self {
match value {
Some(value) => DataValue::String(value),
None => DataValue::Null,
}
}
}
impl From<Option<&str>> for DataValue {
fn from(value: Option<&str>) -> Self {
DataValue::from(value.map(|x| x.to_string()))
}
}
impl From<Option<&String>> for DataValue {
fn from(value: Option<&String>) -> Self {
DataValue::from(value.cloned())
}
}
impl From<Option<&smartstring::alias::String>> for DataValue {
fn from(value: Option<&smartstring::alias::String>) -> Self {
DataValue::from(value.cloned())
}
}
impl From<Vec<DataValue>> for DataValue {
fn from(value: Vec<DataValue>) -> Self {
DataValue::Vec(value)
}
}
impl From<Vec<String>> for DataValue {
fn from(value: Vec<String>) -> Self {
DataValue::Vec(value.into_iter().map(|x| x.into()).collect())
}
}
impl From<&[u8]> for DataValue {
fn from(value: &[u8]) -> Self {
DataValue::Bytes(value.to_vec())
}
}
impl From<Vec<smartstring::alias::String>> for DataValue {
fn from(value: Vec<smartstring::alias::String>) -> Self {
DataValue::Vec(value.into_iter().map(|x| x.into()).collect())
}
}
impl From<Vec<usize>> for DataValue {
fn from(value: Vec<usize>) -> Self {
DataValue::Vec(value.into_iter().map(|x| (x as u32).into()).collect())
}
}
impl From<HashMap<String, DataValue>> for DataValue {
fn from(value: HashMap<String, DataValue>) -> Self {
DataValue::Map(value.into_iter().map(|(k, v)| (k.into(), v)).collect())
}
}
impl From<HashMap<smartstring::alias::String, DataValue>> for DataValue {
fn from(value: HashMap<smartstring::alias::String, DataValue>) -> Self {
DataValue::Map(value)
}
}
impl From<&prost_reflect::Value> for DataValue {
fn from(proto_value: &prost_reflect::Value) -> Self {
match proto_value {
prost_reflect::Value::Bool(b) => DataValue::Bool(*b),
prost_reflect::Value::I32(b) => DataValue::I32(*b),
prost_reflect::Value::I64(b) => DataValue::I64(*b),
prost_reflect::Value::U32(b) => DataValue::U32(*b),
prost_reflect::Value::U64(b) => DataValue::U64(*b),
prost_reflect::Value::F32(b) => DataValue::F32(*b),
prost_reflect::Value::F64(b) => DataValue::F64(*b),
prost_reflect::Value::String(b) => DataValue::String(b.into()),
prost_reflect::Value::Bytes(b) => DataValue::Bytes(b.to_vec()),
prost_reflect::Value::EnumNumber(b) => DataValue::EnumNumber(*b),
prost_reflect::Value::List(b) => DataValue::Vec(b.iter().map(|x| x.into()).collect()),
prost_reflect::Value::Map(b) => DataValue::Map(
b.iter()
.map(|(k, v)| {
let key = match k {
prost_reflect::MapKey::String(k) => k.clone(),
prost_reflect::MapKey::U32(k) => k.to_string(),
prost_reflect::MapKey::U64(k) => k.to_string(),
prost_reflect::MapKey::I32(k) => k.to_string(),
prost_reflect::MapKey::I64(k) => k.to_string(),
prost_reflect::MapKey::Bool(k) => k.to_string(),
};
(key.into(), DataValue::from(v))
})
.collect::<HashMap<_, _>>(),
),
e => {
tracing::trace!("e: {:?}", e);
DataValue::Null
}
}
}
}
impl From<prost_reflect::Value> for DataValue {
fn from(proto_value: prost_reflect::Value) -> Self {
DataValue::from(&proto_value)
}
}
impl From<&serde_json::Value> for DataValue {
fn from(proto_value: &serde_json::Value) -> Self {
match proto_value {
serde_json::Value::Bool(b) => DataValue::Bool(*b),
serde_json::Value::Number(b) => {
if b.is_i64() {
DataValue::I64(b.as_i64().expect("BUG: should be i64"))
} else if b.is_u64() {
DataValue::U64(b.as_u64().expect("BUG: should be u64"))
} else {
DataValue::F64(b.as_f64().expect("BUG: should be f64"))
}
}
serde_json::Value::String(b) => DataValue::String(b.into()),
serde_json::Value::Null => DataValue::Null,
serde_json::Value::Array(v) => DataValue::Vec(v.iter().map(DataValue::from).collect()),
serde_json::Value::Object(v) => DataValue::Map(
v.iter()
.map(|(k, v)| (k.clone().into(), DataValue::from(v)))
.collect(),
),
}
}
}
impl From<serde_json::Value> for DataValue {
fn from(proto_value: serde_json::Value) -> Self {
DataValue::from(&proto_value)
}
}
use base64::{
alphabet,
engine::{self, general_purpose},
Engine as _,
};
const CUSTOM_ENGINE: engine::GeneralPurpose =
engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::NO_PAD);
use serde_json::json;
impl DataValue {
#[inline]
pub fn to_json(self) -> serde_json::Value {
match self {
DataValue::Bool(b) => serde_json::Value::Bool(b),
DataValue::U32(b) => serde_json::Value::Number(b.into()),
DataValue::I32(b) => serde_json::Value::Number(b.into()),
DataValue::U8(b) => serde_json::Value::Number(b.into()),
DataValue::U64(b) => serde_json::Value::Number(b.into()),
DataValue::I64(b) => serde_json::Value::Number(b.into()),
DataValue::F32(b) => json!(b),
DataValue::F64(b) => json!(b),
DataValue::U128(b) => json!(b),
DataValue::I128(b) => json!(b),
DataValue::String(b) => serde_json::Value::String(b.into()),
DataValue::Bytes(b) => serde_json::Value::String(CUSTOM_ENGINE.encode(b)),
DataValue::Null => serde_json::Value::Null,
DataValue::Vec(b) => {
serde_json::Value::Array(b.into_iter().map(|x| x.to_json()).collect())
}
DataValue::Map(b) => serde_json::Value::Object(
b.into_iter()
.map(|(k, v)| (k.to_string(), v.to_json()))
.collect(),
),
DataValue::EnumNumber(b) => serde_json::Value::Number(b.into()),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use rstest::*;
#[rstest]
fn data_value_from() {
assert_eq!(
DataValue::String("key".into()),
DataValue::from(Some("key"))
);
assert_eq!(
DataValue::String("key".into()),
DataValue::from(Some("key".to_string()))
);
assert_eq!(
DataValue::String("key".into()),
DataValue::from(Some(smartstring::alias::String::from("key")))
);
assert_eq!(
DataValue::String("key".into()),
DataValue::from(Some(&smartstring::alias::String::from("key")))
);
assert_eq!(
DataValue::Vec(vec![DataValue::String("key".into())]),
DataValue::Vec(vec![DataValue::from(Some("key"))])
);
assert_eq!(
DataValue::Vec(vec![DataValue::String("key".into())]),
DataValue::Vec(vec![DataValue::from(smartstring::alias::String::from(
"key"
))])
);
let map: HashMap<String, DataValue> =
crate::stdhashmap!(String::from("key") => DataValue::String("key".into()));
assert_eq!(
DataValue::from(map),
DataValue::Map(crate::stdhashmap!("key" => DataValue::from("key")))
);
let map: HashMap<smartstring::alias::String, DataValue> = crate::stdhashmap!(smartstring::alias::String::from("key") => DataValue::String("key".into()));
assert_eq!(
DataValue::from(map),
DataValue::Map(crate::stdhashmap!("key" => DataValue::from("key")))
);
}
#[rstest]
#[case(DataValue::U32(12), serde_json::json!(12))]
#[case(DataValue::I32(12), serde_json::json!(12))]
#[case(DataValue::I64(12), serde_json::json!(12))]
#[case(DataValue::U64(12), serde_json::json!(12))]
#[case(DataValue::F32(12f32), serde_json::json!(12f32))]
#[case(DataValue::F64(12f64), serde_json::json!(12f64))]
#[case(DataValue::U8(12), serde_json::json!(12))]
#[case(DataValue::U128(12), serde_json::json!(12))]
#[case(DataValue::I128(12), serde_json::json!(12))]
#[case(DataValue::Bool(true), serde_json::json!(true))]
#[case(DataValue::Null, serde_json::json!(null))]
#[case(DataValue::Vec(vec![1.into(),2.into(),3.into(),4.into()]), serde_json::json!(vec![1,2,3,4]))]
#[case(DataValue::String("test".into()), serde_json::json!("test"))]
#[case(DataValue::Map(crate::stdhashmap!("key" => "test")), serde_json::json!({"key": "test"}))]
#[case(DataValue::Bytes(vec![1,2,3,4]), serde_json::json!("AQIDBA"))]
fn from_json(#[case] input: DataValue, #[case] expected: serde_json::Value) {
assert_eq!(input.to_json(), expected);
}
#[rstest]
#[case(DataValue::I64(i64::MAX), serde_json::json!(i64::MAX))]
#[case(DataValue::I64(i32::MAX as i64), serde_json::json!(i32::MAX))]
#[case(DataValue::F64(f32::MAX as f64), serde_json::json!(f32::MAX))]
#[case(DataValue::F64(f64::MAX), serde_json::json!(f64::MAX))]
#[case(DataValue::Bool(true), serde_json::json!(true))]
#[case(DataValue::Null, serde_json::json!(null))]
#[case(DataValue::Vec(vec![1i64.into(),2i64.into(),3i64.into(),4i64.into()]), serde_json::json!(vec![1,2,3,4]))]
#[case(DataValue::String("test".into()), serde_json::json!("test"))]
#[case(DataValue::Map(crate::stdhashmap!("key" => "test")), serde_json::json!({"key": "test"}))]
fn to_json(#[case] expected: DataValue, #[case] input: serde_json::Value) {
assert_eq!(DataValue::from(&input), expected);
}
#[rstest]
#[case(DataValue::I64(i64::MAX), prost_reflect::Value::I64(i64::MAX))]
#[case(DataValue::I32(i32::MAX), prost_reflect::Value::I32(i32::MAX))]
#[case(DataValue::F32(f32::MAX), prost_reflect::Value::F32(f32::MAX))]
#[case(DataValue::F64(f64::MAX), prost_reflect::Value::F64(f64::MAX))]
#[case(DataValue::Bool(true), prost_reflect::Value::Bool(true))]
#[case(DataValue::Vec(vec![1i64.into(),2i64.into(),3i64.into(),4i64.into()]), prost_reflect::Value::List(vec![prost_reflect::Value::I64(1),prost_reflect::Value::I64(2),prost_reflect::Value::I64(3),prost_reflect::Value::I64(4)]))]
#[case(DataValue::String("test".into()), prost_reflect::Value::String("test".to_string()))]
#[case(DataValue::Map(crate::stdhashmap!("key" => "test")), prost_reflect::Value::Map(crate::stdhashmap!(prost_reflect::MapKey::String("key".to_string()) => prost_reflect::Value::String("test".to_string()))))]
fn from_prost(#[case] expected: DataValue, #[case] input: prost_reflect::Value) {
assert_eq!(DataValue::from(&input), expected);
}
}