1use crate::Modalias;
2use crate::{AddressType, BluetoothError, MacAddress};
3use bluez_generated::OrgBluezAdapter1Properties;
4use dbus::Path;
5use serde::{Deserialize, Serialize};
6use std::fmt::{self, Display, Formatter};
7
8#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
10pub struct AdapterId {
11 #[serde(with = "crate::serde_path")]
12 pub(crate) object_path: Path<'static>,
13}
14
15impl AdapterId {
16 pub(crate) fn new(object_path: &str) -> Self {
17 Self {
18 object_path: object_path.to_owned().into(),
19 }
20 }
21}
22
23impl From<AdapterId> for Path<'static> {
24 fn from(id: AdapterId) -> Self {
25 id.object_path
26 }
27}
28
29impl Display for AdapterId {
30 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
31 write!(
32 f,
33 "{}",
34 self.object_path
35 .to_string()
36 .strip_prefix("/org/bluez/")
37 .ok_or(fmt::Error)?
38 )
39 }
40}
41
42#[derive(Clone, Debug, Eq, PartialEq)]
44pub struct AdapterInfo {
45 pub id: AdapterId,
47 pub mac_address: MacAddress,
49 pub address_type: AddressType,
51 pub name: String,
53 pub alias: String,
55 pub modalias: Modalias,
57 pub powered: bool,
59 pub discovering: bool,
61}
62
63impl AdapterInfo {
64 pub(crate) fn from_properties(
65 id: AdapterId,
66 adapter_properties: OrgBluezAdapter1Properties,
67 ) -> Result<AdapterInfo, BluetoothError> {
68 let mac_address = adapter_properties
69 .address()
70 .ok_or(BluetoothError::RequiredPropertyMissing("Address"))?
71 .parse()?;
72 let address_type = adapter_properties
73 .address_type()
74 .ok_or(BluetoothError::RequiredPropertyMissing("AddressType"))?
75 .parse()?;
76 let modalias = adapter_properties
77 .modalias()
78 .ok_or(BluetoothError::RequiredPropertyMissing("Modalias"))?
79 .parse()?;
80
81 Ok(AdapterInfo {
82 id,
83 mac_address,
84 address_type,
85 name: adapter_properties
86 .name()
87 .ok_or(BluetoothError::RequiredPropertyMissing("Name"))?
88 .to_owned(),
89 alias: adapter_properties
90 .alias()
91 .ok_or(BluetoothError::RequiredPropertyMissing("Alias"))?
92 .to_owned(),
93 modalias,
94 powered: adapter_properties
95 .powered()
96 .ok_or(BluetoothError::RequiredPropertyMissing("Powered"))?,
97 discovering: adapter_properties
98 .discovering()
99 .ok_or(BluetoothError::RequiredPropertyMissing("Discovering"))?,
100 })
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use crate::modalias::ModaliasSubtype;
108 use dbus::arg::{PropMap, Variant};
109 use std::collections::HashMap;
110
111 #[test]
112 fn adapter_info_minimal() {
113 let id = AdapterId::new("/org/bluez/hci0");
114 let mut adapter_properties: PropMap = HashMap::new();
115 adapter_properties.insert(
116 "Address".to_string(),
117 Variant(Box::new("00:11:22:33:44:55".to_string())),
118 );
119 adapter_properties.insert(
120 "AddressType".to_string(),
121 Variant(Box::new("public".to_string())),
122 );
123 adapter_properties.insert("Name".to_string(), Variant(Box::new("name".to_string())));
124 adapter_properties.insert("Alias".to_string(), Variant(Box::new("alias".to_string())));
125 adapter_properties.insert(
126 "Modalias".to_string(),
127 Variant(Box::new("usb:v1234p5678d90AB".to_string())),
128 );
129 adapter_properties.insert("Powered".to_string(), Variant(Box::new(false)));
130 adapter_properties.insert("Discovering".to_string(), Variant(Box::new(false)));
131
132 let adapter = AdapterInfo::from_properties(
133 id.clone(),
134 OrgBluezAdapter1Properties(&adapter_properties),
135 )
136 .unwrap();
137 assert_eq!(
138 adapter,
139 AdapterInfo {
140 id,
141 mac_address: "00:11:22:33:44:55".parse().unwrap(),
142 address_type: AddressType::Public,
143 name: "name".to_string(),
144 alias: "alias".to_string(),
145 modalias: Modalias {
146 subtype: ModaliasSubtype::Usb,
147 vendor_id: 0x1234,
148 product_id: 0x5678,
149 device_id: 0x90ab
150 },
151 powered: false,
152 discovering: false
153 }
154 )
155 }
156
157 #[test]
158 fn to_string() {
159 let adapter_id = AdapterId::new("/org/bluez/hci0");
160 assert_eq!(adapter_id.to_string(), "hci0");
161 }
162}