-
Notifications
You must be signed in to change notification settings - Fork 43
/
dbus.rs
119 lines (104 loc) · 3.96 KB
/
dbus.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use std::collections::HashMap;
use zbus::zvariant::{self, OwnedObjectPath, OwnedValue, Value};
/// Nested hash to send to D-Bus.
pub type NestedHash<'a> = HashMap<&'a str, HashMap<&'a str, zvariant::Value<'a>>>;
/// Nested hash as it comes from D-Bus.
pub type OwnedNestedHash = HashMap<String, HashMap<String, zvariant::OwnedValue>>;
/// Helper to get property of given type from ManagedObjects map or any generic D-Bus Hash with variant as value
pub fn get_property<'a, T>(
properties: &'a HashMap<String, OwnedValue>,
name: &str,
) -> Result<T, zbus::zvariant::Error>
where
T: TryFrom<Value<'a>>,
<T as TryFrom<Value<'a>>>::Error: Into<zbus::zvariant::Error>,
{
let value: Value = properties
.get(name)
.ok_or(zbus::zvariant::Error::Message(format!(
"Failed to find property '{}'",
name
)))?
.into();
T::try_from(value).map_err(|e| e.into())
}
/// It is similar helper like get_property with difference that name does not need to be in HashMap.
/// In such case `None` is returned, so type has to be enclosed in `Option`.
pub fn get_optional_property<'a, T>(
properties: &'a HashMap<String, OwnedValue>,
name: &str,
) -> Result<Option<T>, zbus::zvariant::Error>
where
T: TryFrom<Value<'a>>,
<T as TryFrom<Value<'a>>>::Error: Into<zbus::zvariant::Error>,
{
if let Some(value) = properties.get(name) {
let value: Value = value.into();
T::try_from(value).map(|v| Some(v)).map_err(|e| e.into())
} else {
Ok(None)
}
}
#[macro_export]
macro_rules! property_from_dbus {
($self:ident, $field:ident, $key:expr, $dbus:ident, $type:ty) => {
if let Some(v) = get_optional_property($dbus, $key)? {
$self.$field = v;
}
};
}
/// Converts a hash map containing zbus non-owned values to hash map with owned ones.
///
/// NOTE: we could follow a different approach like building our own type (e.g.
/// using the newtype idiom) and offering a better API.
///
/// * `source`: hash map containing non-onwed values ([enum@zbus::zvariant::Value]).
pub fn to_owned_hash(source: &HashMap<&str, Value<'_>>) -> HashMap<String, OwnedValue> {
let mut owned = HashMap::new();
for (key, value) in source.iter() {
owned.insert(key.to_string(), value.into());
}
owned
}
/// Extracts the object ID from the path.
///
/// TODO: should we merge this feature with the "DeviceSid"?
pub fn extract_id_from_path(path: &OwnedObjectPath) -> Result<u32, zvariant::Error> {
path.as_str()
.rsplit_once('/')
.and_then(|(_, id)| id.parse::<u32>().ok())
.ok_or_else(|| {
zvariant::Error::Message(format!("Could not extract the ID from {}", path.as_str()))
})
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use zbus::zvariant::{self, OwnedValue, Str};
use crate::dbus::{get_optional_property, get_property};
#[test]
fn test_get_property() {
let data: HashMap<String, OwnedValue> = HashMap::from([
("Id".to_string(), 1_u8.into()),
("Device".to_string(), Str::from_static("/dev/sda").into()),
]);
let id: u8 = get_property(&data, "Id").unwrap();
assert_eq!(id, 1);
let device: String = get_property(&data, "Device").unwrap();
assert_eq!(device, "/dev/sda".to_string());
}
#[test]
fn test_get_property_wrong_type() {
let data: HashMap<String, OwnedValue> = HashMap::from([("Id".to_string(), 1_u8.into())]);
let result: Result<u16, _> = get_property(&data, "Id");
assert_eq!(result, Err(zvariant::Error::IncorrectType));
}
#[test]
fn test_get_optional_property() {
let data: HashMap<String, OwnedValue> = HashMap::from([("Id".to_string(), 1_u8.into())]);
let id: Option<u8> = get_optional_property(&data, "Id").unwrap();
assert_eq!(id, Some(1));
let device: Option<String> = get_optional_property(&data, "Device").unwrap();
assert_eq!(device, None);
}
}