1use std::{collections::HashSet, marker::PhantomData, sync::Arc};
2
3use zbus_names::{BusName, InterfaceName};
4use zvariant::{ObjectPath, Str};
5
6use crate::{proxy::ProxyInner, Connection, Error, Proxy, Result};
7
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
10#[non_exhaustive]
11pub enum CacheProperties {
12 Yes,
15 No,
17 #[default]
19 Lazily,
20}
21
22#[derive(Debug)]
24pub struct Builder<'a, T = ()> {
25 conn: Connection,
26 destination: Option<BusName<'a>>,
27 path: Option<ObjectPath<'a>>,
28 interface: Option<InterfaceName<'a>>,
29 proxy_type: PhantomData<T>,
30 cache: CacheProperties,
31 uncached_properties: Option<HashSet<Str<'a>>>,
32}
33
34impl<T> Clone for Builder<'_, T> {
35 fn clone(&self) -> Self {
36 Self {
37 conn: self.conn.clone(),
38 destination: self.destination.clone(),
39 path: self.path.clone(),
40 interface: self.interface.clone(),
41 cache: self.cache,
42 uncached_properties: self.uncached_properties.clone(),
43 proxy_type: PhantomData,
44 }
45 }
46}
47
48impl<'a, T> Builder<'a, T> {
49 pub fn destination<D>(mut self, destination: D) -> Result<Self>
51 where
52 D: TryInto<BusName<'a>>,
53 D::Error: Into<Error>,
54 {
55 self.destination = Some(destination.try_into().map_err(Into::into)?);
56 Ok(self)
57 }
58
59 pub fn path<P>(mut self, path: P) -> Result<Self>
61 where
62 P: TryInto<ObjectPath<'a>>,
63 P::Error: Into<Error>,
64 {
65 self.path = Some(path.try_into().map_err(Into::into)?);
66 Ok(self)
67 }
68
69 pub fn interface<I>(mut self, interface: I) -> Result<Self>
71 where
72 I: TryInto<InterfaceName<'a>>,
73 I::Error: Into<Error>,
74 {
75 self.interface = Some(interface.try_into().map_err(Into::into)?);
76 Ok(self)
77 }
78
79 #[must_use]
81 pub fn cache_properties(mut self, cache: CacheProperties) -> Self {
82 self.cache = cache;
83 self
84 }
85
86 #[must_use]
88 pub fn uncached_properties(mut self, properties: &[&'a str]) -> Self {
89 self.uncached_properties
90 .replace(properties.iter().map(|p| Str::from(*p)).collect());
91
92 self
93 }
94
95 pub(crate) fn build_internal(self) -> Result<Proxy<'a>> {
96 let conn = self.conn;
97 let destination = self
98 .destination
99 .ok_or(Error::MissingParameter("destination"))?;
100 let path = self.path.ok_or(Error::MissingParameter("path"))?;
101 let interface = self.interface.ok_or(Error::MissingParameter("interface"))?;
102 let cache = self.cache;
103 let uncached_properties = self.uncached_properties.unwrap_or_default();
104
105 Ok(Proxy {
106 inner: Arc::new(ProxyInner::new(
107 conn,
108 destination,
109 path,
110 interface,
111 cache,
112 uncached_properties,
113 )),
114 })
115 }
116
117 pub async fn build(self) -> Result<T>
124 where
125 T: From<Proxy<'a>>,
126 {
127 let cache_upfront = self.cache == CacheProperties::Yes;
128 let proxy = self.build_internal()?;
129
130 if cache_upfront {
131 proxy
132 .get_property_cache()
133 .expect("properties cache not initialized")
134 .ready()
135 .await?;
136 }
137
138 Ok(proxy.into())
139 }
140}
141
142impl<T> Builder<'_, T>
143where
144 T: super::Defaults,
145{
146 #[must_use]
148 pub fn new(conn: &Connection) -> Self {
149 Self {
150 conn: conn.clone(),
151 destination: T::DESTINATION.clone(),
152 path: T::PATH.clone(),
153 interface: T::INTERFACE.clone(),
154 cache: CacheProperties::default(),
155 uncached_properties: None,
156 proxy_type: PhantomData,
157 }
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164 use test_log::test;
165
166 #[test]
167 #[ntest::timeout(15000)]
168 fn builder() {
169 crate::utils::block_on(builder_async());
170 }
171
172 async fn builder_async() {
173 let conn = Connection::session().await.unwrap();
174
175 let builder = Builder::<Proxy<'_>>::new(&conn)
176 .destination("org.freedesktop.DBus")
177 .unwrap()
178 .path("/some/path")
179 .unwrap()
180 .interface("org.freedesktop.Interface")
181 .unwrap()
182 .cache_properties(CacheProperties::No);
183 assert!(matches!(
184 builder.clone().destination.unwrap(),
185 BusName::Unique(_),
186 ));
187 let proxy = builder.build().await.unwrap();
188 assert!(matches!(proxy.inner.destination, BusName::Unique(_)));
189 }
190}