use std::collections::{BTreeMap, HashMap};
use endi::NATIVE_ENDIAN;
use zvariant::{
DeserializeDict, Dict, SerializeDict, Str, Type, Value, as_value::optional,
serialized::Context, to_bytes,
};
#[macro_use]
mod common {
include!("common.rs");
}
#[test]
fn dict_value() {
let mut map: HashMap<i64, &str> = HashMap::new();
map.insert(1, "123");
map.insert(2, "456");
let ctxt = Context::new_dbus(NATIVE_ENDIAN, 0);
let encoded = to_bytes(ctxt, &map).unwrap();
assert_eq!(dbg!(encoded.len()), 40);
let decoded: HashMap<i64, &str> = encoded.deserialize().unwrap().0;
assert_eq!(decoded[&1], "123");
assert_eq!(decoded[&2], "456");
#[cfg(feature = "gvariant")]
{
let ctxt = Context::new_gvariant(NATIVE_ENDIAN, 0);
let gv_encoded = to_bytes(ctxt, &map).unwrap();
assert_eq!(gv_encoded.len(), 30);
let map: HashMap<i64, &str> = encoded.deserialize().unwrap().0;
assert_eq!(map[&1], "123");
assert_eq!(map[&2], "456");
}
let ctxt = Context::new_dbus(NATIVE_ENDIAN, 0);
let v: Value<'_> = Dict::from(map).into();
assert_eq!(v.value_signature(), "a{xs}");
let encoded = to_bytes(ctxt, &v).unwrap();
assert_eq!(encoded.len(), 48);
let dict: Dict<'_, '_> = v.try_into().unwrap();
let map: HashMap<i64, String> = dict.try_clone().unwrap().try_into().unwrap();
assert_eq!(map[&1], "123");
assert_eq!(map[&2], "456");
let v = encoded.deserialize().unwrap().0;
if let Value::Dict(dict) = v {
assert_eq!(dict.get::<i64, &str>(&1).unwrap().unwrap(), "123");
assert_eq!(dict.get::<i64, &str>(&2).unwrap().unwrap(), "456");
} else {
panic!();
}
let map: BTreeMap<i64, String> = dict.try_into().unwrap();
assert_eq!(map[&1], "123");
assert_eq!(map[&2], "456");
let mut dict = Dict::from(map);
let expect = [
(Value::from(1i64), Value::from("123")),
(Value::from(2i64), Value::from("456")),
];
let expect_iter = expect.iter().map(|(k, v)| (k, v)).collect::<Vec<_>>();
let actual = dict.iter().collect::<Vec<_>>();
assert_eq!(actual, expect_iter);
let actual = dict.iter().collect::<Vec<_>>();
assert_eq!(actual, expect_iter);
let actual = dict.iter().collect::<Vec<_>>();
assert_eq!(actual, expect_iter);
for (_, v) in dict.iter_mut() {
if let Value::Str(vv) = v {
*vv = Str::from(vv.to_string() + "-hello");
}
}
let actual = dict.into_iter().collect::<Vec<_>>();
let expect = vec![
(Value::from(1i64), Value::from("123-hello")),
(Value::from(2i64), Value::from("456-hello")),
];
assert_eq!(actual, expect);
#[cfg(feature = "gvariant")]
{
let mut map: HashMap<&str, &str> = HashMap::new();
map.insert("hi", "1234");
map.insert("world", "561");
let ctxt = Context::new_gvariant(NATIVE_ENDIAN, 0);
let gv_encoded = to_bytes(ctxt, &map).unwrap();
assert_eq!(gv_encoded.len(), 22);
let map: HashMap<&str, &str> = gv_encoded.deserialize().unwrap().0;
assert_eq!(map["hi"], "1234");
assert_eq!(map["world"], "561");
let mut map = std::collections::HashMap::<&str, &str>::new();
map.insert("k", "v");
let gv_ser_value_encoded =
zvariant::to_bytes(ctxt, &zvariant::as_value::Serialize(&map)).unwrap();
let gv_value_encoded = to_bytes(ctxt, &zvariant::Value::new(map)).unwrap();
assert_eq!(*gv_value_encoded, *gv_ser_value_encoded);
let map: HashMap<&str, &str> = HashMap::new();
let gv_encoded = to_bytes(ctxt, &map).unwrap();
assert_eq!(gv_encoded.len(), 0);
let map: HashMap<&str, &str> = gv_encoded.deserialize().unwrap().0;
assert_eq!(map.len(), 0);
}
let ctxt = Context::new_dbus(NATIVE_ENDIAN, 0);
let mut dict = Dict::new(<&str>::SIGNATURE, Value::SIGNATURE);
dict.add("hello", Value::new("there")).unwrap();
dict.add("bye", Value::new("now")).unwrap();
let v: Value<'_> = dict.into();
assert_eq!(v.value_signature(), "a{sv}");
let encoded = to_bytes(ctxt, &v).unwrap();
assert_eq!(dbg!(encoded.len()), 66);
let v: Value<'_> = encoded.deserialize().unwrap().0;
if let Value::Dict(dict) = v {
assert_eq!(
dict.get::<&str, Value<'_>>(&"hello").unwrap().unwrap(),
Value::new("there")
);
assert_eq!(
dict.get::<_, Value<'_>>(&"bye").unwrap().unwrap(),
Value::new("now")
);
let map = <HashMap<String, Value<'_>>>::try_from(dict.try_clone().unwrap()).unwrap();
assert_eq!(map["hello"], Value::new("there"));
assert_eq!(map["bye"], Value::new("now"));
let map = <BTreeMap<String, Value<'_>>>::try_from(dict).unwrap();
assert_eq!(map["hello"], Value::new("there"));
assert_eq!(map["bye"], Value::new("now"));
} else {
panic!();
}
#[derive(DeserializeDict, SerializeDict, Type, PartialEq, Debug, Default)]
#[zvariant(signature = "a{sv}")]
struct Test {
process_id: Option<u32>,
group_id: Option<u32>,
user: String,
}
let test = Test {
process_id: Some(42),
group_id: None,
user: "me".to_string(),
};
let encoded = to_bytes(ctxt, &test).unwrap();
assert_eq!(encoded.len(), 51);
let decoded: HashMap<&str, Value<'_>> = encoded.deserialize().unwrap().0;
assert_eq!(decoded["process_id"], Value::U32(42));
assert_eq!(decoded["user"], Value::new("me"));
assert!(!decoded.contains_key("group_id"));
let decoded: Test = encoded.deserialize().unwrap().0;
assert_eq!(decoded, test);
#[derive(DeserializeDict, SerializeDict, Type, PartialEq, Debug)]
#[zvariant(signature = "a{sv}")]
struct TestMissing {
process_id: Option<u32>,
group_id: Option<u32>,
user: String,
quota: u8,
}
let decoded = encoded.deserialize::<TestMissing>();
assert!(decoded.is_err());
#[derive(DeserializeDict, SerializeDict, Type, PartialEq, Debug, Default)]
#[zvariant(signature = "a{sv}")]
struct TestSkipUnknown {
process_id: Option<u32>,
group_id: Option<u32>,
}
let _: TestSkipUnknown = encoded.deserialize().unwrap().0;
#[derive(DeserializeDict, SerializeDict, Type, PartialEq, Debug, Default)]
#[zvariant(signature = "a{sv}", deny_unknown_fields)]
struct TestDenyUnknown {
process_id: Option<u32>,
group_id: Option<u32>,
}
let decoded = encoded.deserialize::<TestDenyUnknown>();
assert!(decoded.is_err());
#[derive(serde::Serialize, serde::Deserialize, Type, PartialEq, Debug, Default)]
#[serde(default)]
#[zvariant(signature = "a{sv}")]
struct TestParseUnknown<'s> {
#[serde(with = "optional", skip_serializing_if = "Option::is_none")]
process_id: Option<u32>,
#[serde(with = "optional", skip_serializing_if = "Option::is_none")]
group_id: Option<u32>,
#[serde(flatten, borrow)]
rest: HashMap<&'s str, Value<'s>>,
}
let decoded: TestParseUnknown<'_> = encoded.deserialize().unwrap().0;
assert_eq!(decoded.rest.len(), 1);
assert_eq!(decoded.rest["user"], Value::new("me"));
#[cfg(feature = "gvariant")]
{
let test = Test {
process_id: Some(42),
group_id: None,
user: "me".to_string(),
};
let ctxt = Context::new_gvariant(NATIVE_ENDIAN, 0);
let encoded = to_bytes(ctxt, &test).unwrap();
let _: Test = encoded.deserialize().unwrap().0;
let decoded = encoded.deserialize::<TestMissing>();
assert!(decoded.is_err());
let _: TestSkipUnknown = encoded.deserialize().unwrap().0;
let decoded = encoded.deserialize::<TestDenyUnknown>();
assert!(decoded.is_err());
}
#[derive(Default, Debug, SerializeDict, DeserializeDict, Type)]
#[zvariant(signature = "dict")]
struct TestEmpty {}
let data = to_bytes(ctxt, &TestEmpty::default()).unwrap();
assert_eq!(data.bytes(), &[0, 0, 0, 0, 0, 0, 0, 0]);
}