1#![doc = include_str!("../README.md")]
2use std::{env, fmt};
3
4pub mod transport;
5
6mod address;
7pub use address::{DBusAddr, ToDBusAddrs};
8
9mod owned_address;
10pub use owned_address::{OwnedDBusAddr, ToOwnedDBusAddrs};
11
12mod address_list;
13pub use address_list::{DBusAddrList, DBusAddrListIter, OwnedDBusAddrListIter};
14
15mod percent;
16pub use percent::*;
17
18mod guid;
19pub use guid::Guid;
20
21#[cfg(test)]
22mod tests;
23
24#[derive(Debug, Clone, Eq, PartialEq)]
26pub enum Error {
27 MissingTransport,
28 Encoding(String),
29 DuplicateKey(String),
30 MissingKey(String),
31 MissingValue(String),
32 InvalidValue(String),
33 UnknownTcpFamily(String),
34 Other(String),
35}
36
37impl fmt::Display for Error {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 match self {
40 Error::MissingTransport => write!(f, "Missing transport in address"),
41 Error::Encoding(e) => write!(f, "Encoding error: {e}"),
42 Error::DuplicateKey(e) => write!(f, "Duplicate key: `{e}`"),
43 Error::MissingKey(e) => write!(f, "Missing key: `{e}`"),
44 Error::MissingValue(e) => write!(f, "Missing value for key: `{e}`"),
45 Error::InvalidValue(e) => write!(f, "Invalid value for key: `{e}`"),
46 Error::UnknownTcpFamily(e) => write!(f, "Unknown TCP address family: `{e}`"),
47 Error::Other(e) => write!(f, "Other error: {e}"),
48 }
49 }
50}
51
52impl std::error::Error for Error {}
53
54pub type Result<T> = std::result::Result<T, Error>;
55
56pub fn session() -> Result<DBusAddrList<'static>> {
60 match env::var("DBUS_SESSION_BUS_ADDRESS") {
61 Ok(val) => DBusAddrList::try_from(val),
62 _ => {
63 #[cfg(windows)]
64 {
65 DBusAddrList::try_from("autolaunch:scope=*user;autolaunch:")
66 }
67
68 #[cfg(all(unix, not(target_os = "macos")))]
69 {
70 #[link(name = "c")]
71 extern "C" {
72 fn geteuid() -> u32;
73 }
74
75 let runtime_dir = env::var("XDG_RUNTIME_DIR")
76 .unwrap_or_else(|_| format!("/run/user/{}", unsafe { geteuid() }));
77 let path = format!("unix:path={runtime_dir}/bus");
78
79 DBusAddrList::try_from(path)
80 }
81
82 #[cfg(target_os = "macos")]
83 {
84 DBusAddrList::try_from("launchd:env=DBUS_LAUNCHD_SESSION_BUS_SOCKET")
85 }
86 }
87 }
88}
89
90pub fn system() -> Result<DBusAddrList<'static>> {
94 match env::var("DBUS_SYSTEM_BUS_ADDRESS") {
95 Ok(val) => DBusAddrList::try_from(val),
96 _ => {
97 #[cfg(all(unix, not(target_os = "macos")))]
98 return DBusAddrList::try_from("unix:path=/var/run/dbus/system_bus_socket");
99
100 #[cfg(windows)]
101 return DBusAddrList::try_from("autolaunch:");
102
103 #[cfg(target_os = "macos")]
104 return DBusAddrList::try_from("launchd:env=DBUS_LAUNCHD_SESSION_BUS_SOCKET");
105 }
106 }
107}
108
109struct KeyValIter<'a> {
110 data: &'a str,
111 next_index: usize,
112}
113
114impl<'a> KeyValIter<'a> {
115 fn new(data: &'a str) -> Self {
116 KeyValIter {
117 data,
118 next_index: 0,
119 }
120 }
121}
122
123impl<'a> Iterator for KeyValIter<'a> {
124 type Item = (&'a str, Option<&'a str>);
125
126 fn next(&mut self) -> Option<Self::Item> {
127 if self.next_index >= self.data.len() {
128 return None;
129 }
130
131 let mut pair = &self.data[self.next_index..];
132 if let Some(end) = pair.find(',') {
133 pair = &pair[..end];
134 self.next_index += end + 1;
135 } else {
136 self.next_index = self.data.len();
137 }
138 let mut split = pair.split('=');
139 let key = split.next().unwrap();
141
142 Some((key, split.next()))
143 }
144}
145
146pub(crate) struct KeyValFmt<'a> {
151 fields: Vec<(Box<dyn fmt::Display + 'a>, Box<dyn Encodable + 'a>)>,
152}
153
154impl<'a> KeyValFmt<'a> {
155 fn new() -> Self {
156 Self { fields: vec![] }
157 }
158
159 pub(crate) fn add<K, V>(mut self, key: K, val: Option<V>) -> Self
160 where
161 K: fmt::Display + 'a,
162 V: Encodable + 'a,
163 {
164 if let Some(val) = val {
165 self.fields.push((Box::new(key), Box::new(val)));
166 }
167
168 self
169 }
170}
171
172impl fmt::Display for KeyValFmt<'_> {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 let mut first = true;
175 for (k, v) in self.fields.iter() {
176 if !first {
177 write!(f, ",")?;
178 }
179 write!(f, "{k}=")?;
180 v.encode(f)?;
181 first = false;
182 }
183
184 Ok(())
185 }
186}