zbus_macros/
lib.rs

1#![deny(rust_2018_idioms)]
2#![doc(
3    html_logo_url = "https://raw.githubusercontent.com/z-galaxy/zbus/9f7a90d2b594ddc48b7a5f39fda5e00cd56a7dfb/logo.png"
4)]
5#![doc = include_str!("../README.md")]
6#![doc(test(attr(
7    warn(unused),
8    deny(warnings),
9    allow(dead_code),
10    // W/o this, we seem to get some bogus warning about `extern crate zbus`.
11    allow(unused_extern_crates),
12)))]
13
14use proc_macro::TokenStream;
15use syn::{
16    DeriveInput, ItemImpl, ItemTrait, Meta, Token, parse_macro_input, punctuated::Punctuated,
17};
18
19mod error;
20mod iface;
21mod proxy;
22mod utils;
23
24/// Attribute macro for defining D-Bus proxies (using [`zbus::Proxy`] and
25/// [`zbus::blocking::Proxy`]).
26///
27/// The macro must be applied on a `trait T`. Two matching `impl T` will provide an asynchronous
28/// Proxy implementation, named `TraitNameProxy` and a blocking one, named `TraitNameProxyBlocking`.
29/// The proxy instances can be created with the associated `new()` or `builder()` methods. The
30/// former doesn't take any argument and uses the default service name and path. The later allows
31/// you to specify non-default proxy arguments.
32///
33/// The following attributes are supported:
34///
35/// * `interface` - the name of the D-Bus interface this proxy is for.
36///
37/// * `default_service` - the default service this proxy should connect to.
38///
39/// * `default_path` - The default object path the method calls will be sent on and signals will be
40///   sent for by the target service.
41///
42/// * `gen_async` - Whether or not to generate the asynchronous Proxy type.
43///
44/// * `gen_blocking` - Whether or not to generate the blocking Proxy type. If the `blocking-api`
45///   cargo feature is disabled, this attribute is ignored and blocking Proxy type is not generated.
46///
47/// * `async_name` - Specify the exact name of the asynchronous proxy type.
48///
49/// * `blocking_name` - Specify the exact name of the blocking proxy type.
50///
51/// * `assume_defaults` - whether to auto-generate values for `default_path` and `default_service`
52///   if none are specified (default: `false`). `proxy` generates a warning if neither this
53///   attribute nor one of the default values are specified. Please make sure to explicitly set
54///   either this attribute or the default values, according to your needs.
55///
56/// * `crate` - specify the path to the `zbus` crate if it's renamed or re-exported.
57///
58/// Each trait method will be expanded to call to the associated D-Bus remote interface.
59///
60/// Trait methods accept `proxy` attributes:
61///
62/// * `name` - override the D-Bus name (pascal case form by default)
63///
64/// * `property` - expose the method as a property. If the method takes an argument, it must be a
65///   setter, with a `set_` prefix. Otherwise, it's a getter. Additional sub-attributes exists to
66///   control specific property behaviors:
67///   * `emits_changed_signal` - specifies how property changes are signaled. Valid values are those
68///     documented in [DBus specifications][dbus_emits_changed_signal]:
69///     * `"true"` - (default) change signal is always emitted with the value included. This uses
70///       the default caching behavior of the proxy, and generates a listener method for the change
71///       signal.
72///     * `"invalidates"` - change signal is emitted, but the value is not included in the signal.
73///       This has the same behavior as `"true"`.
74///     * `"const"` - property never changes, thus no signal is ever emitted for it. This uses the
75///       default caching behavior of the proxy, but does not generate a listener method for the
76///       change signal.
77///     * `"false"` - change signal is not (guaranteed to be) emitted if the property changes. This
78///       disables property value caching, and does not generate a listener method for the change
79///       signal.
80///
81/// * `signal` - declare a signal just like a D-Bus method. Read the [Signals](#signals) section
82///   below for details.
83///
84/// * `no_reply` - declare a method call that does not wait for a reply.
85///
86/// * `no_autostart` - declare a method call that will not trigger the bus to automatically launch
87///   the destination service if it is not already running.
88///
89/// * `allow_interactive_auth` - declare a method call that is allowed to trigger an interactive
90///   prompt for authorization or confirmation from the receiver.
91///
92/// * `object` - methods or properties that return an [`ObjectPath`] can be annotated with the
93///   `object` attribute to specify the proxy object to be constructed from the returned
94///   [`ObjectPath`].
95///
96/// * `async_object` - if the assumptions made by `object` attribute about naming of the
97///   asynchronous proxy type, don't fit your bill, you can use this to specify its exact name.
98///
99/// * `blocking_object` - if the assumptions made by `object` attribute about naming of the blocking
100///   proxy type, don't fit your bill, you can use this to specify its exact name.
101///
102/// * `object_vec` - this method returns a list of [`ObjectPath`]s (DBus signature `ao`) that should
103///   be converted to the proxy object type named by `object`, `async_object` and `blocking_object`
104///   attributes, and returned as a `Vec<_>`.
105///
106///   NB: Any doc comments provided shall be appended to the ones added by the macro.
107///
108/// # Signals
109///
110/// For each signal method declared, this macro will provide a method, named `receive_<method_name>`
111/// to create a [`zbus::SignalStream`] ([`zbus::blocking::SignalIterator`] for the blocking proxy)
112/// wrapper, named `<SignalName>Stream` (`<SignalName>Iterator` for the blocking proxy) that yield
113/// a [`zbus::message::Message`] wrapper, named `<SignalName>`. This wrapper provides type safe
114/// access to the signal arguments. It also implements `Deref<Target = Message>` to allow easy
115/// access to the underlying [`zbus::message::Message`].
116///
117/// For each property with `emits_changed_signal` set to `"true"` (default) or `"invalidates"`,
118/// this macro will provide a method named `receive_<property_name>_changed` that creates a
119/// [`zbus::proxy::PropertyStream`] for the property.
120///
121/// # Example
122///
123/// ```no_run
124/// # use std::error::Error;
125/// use zbus::proxy;
126/// use zbus::{blocking::Connection, Result, fdo, zvariant::Value};
127/// use futures_util::stream::StreamExt;
128/// use async_io::block_on;
129///
130/// #[proxy(
131///     interface = "org.test.SomeIface",
132///     default_service = "org.test.SomeService",
133///     default_path = "/org/test/SomeObject"
134/// )]
135/// trait SomeIface {
136///     fn do_this(&self, with: &str, some: u32, arg: &Value<'_>) -> Result<bool>;
137///
138///     #[zbus(property)]
139///     fn a_property(&self) -> fdo::Result<String>;
140///
141///     #[zbus(property)]
142///     fn set_a_property(&self, a_property: &str) -> fdo::Result<()>;
143///
144///     #[zbus(signal)]
145///     fn some_signal(&self, arg1: &str, arg2: u32) -> fdo::Result<()>;
146///
147///     #[zbus(object = "SomeOtherIface", blocking_object = "SomeOtherInterfaceBlock")]
148///     // The method will return a `SomeOtherIfaceProxy` or `SomeOtherIfaceProxyBlock`, depending
149///     // on whether it is called on `SomeIfaceProxy` or `SomeIfaceProxyBlocking`, respectively.
150///     //
151///     // NB: We explicitly specified the exact name of the blocking proxy type. If we hadn't,
152///     // `SomeOtherIfaceProxyBlock` would have been assumed and expected. We could also specify
153///     // the specific name of the asynchronous proxy types, using the `async_object` attribute.
154///     fn some_method(&self, arg1: &str);
155///
156///     #[zbus(property, object = "SomeOtherIface", blocking_object = "SomeOtherInterfaceBlock")]
157///     // Properties that return an ObjectPath can also use the `object` attribute.
158///     fn related_object(&self);
159/// }
160///
161/// #[proxy(
162///     interface = "org.test.SomeOtherIface",
163///     default_service = "org.test.SomeOtherService",
164///     blocking_name = "SomeOtherInterfaceBlock",
165/// )]
166/// trait SomeOtherIface {}
167///
168/// let connection = Connection::session()?;
169/// // Use `builder` to override the default arguments, `new` otherwise.
170/// let proxy = SomeIfaceProxyBlocking::builder(&connection)
171///                .destination("org.another.Service")?
172///                .cache_properties(zbus::proxy::CacheProperties::No)
173///                .build()?;
174/// let _ = proxy.do_this("foo", 32, &Value::new(true));
175/// let _ = proxy.set_a_property("val");
176///
177/// let signal = proxy.receive_some_signal()?.next().unwrap();
178/// let args = signal.args()?;
179/// println!("arg1: {}, arg2: {}", args.arg1(), args.arg2());
180///
181/// // Now the same again, but asynchronous.
182/// block_on(async move {
183///     let proxy = SomeIfaceProxy::builder(&connection.into())
184///                    .cache_properties(zbus::proxy::CacheProperties::No)
185///                    .build()
186///                    .await
187///                    .unwrap();
188///     let _ = proxy.do_this("foo", 32, &Value::new(true)).await;
189///     let _ = proxy.set_a_property("val").await;
190///
191///     let signal = proxy.receive_some_signal().await?.next().await.unwrap();
192///     let args = signal.args()?;
193///     println!("arg1: {}, arg2: {}", args.arg1(), args.arg2());
194///
195///     Ok::<(), zbus::Error>(())
196/// })?;
197///
198/// # Ok::<_, Box<dyn Error + Send + Sync>>(())
199/// ```
200///
201/// [`zbus_polkit`] is a good example of how to bind a real D-Bus API.
202///
203/// [`zbus_polkit`]: https://docs.rs/zbus_polkit/1.0.0/zbus_polkit/policykit1/index.html
204/// [`zbus::Proxy`]: https://docs.rs/zbus/latest/zbus/proxy/struct.Proxy.html
205/// [`zbus::message::Message`]: https://docs.rs/zbus/latest/zbus/message/struct.Message.html
206/// [`zbus::proxy::PropertyStream`]: https://docs.rs/zbus/latest/zbus/proxy/struct.PropertyStream.html
207/// [`zbus::blocking::Proxy`]: https://docs.rs/zbus/latest/zbus/blocking/proxy/struct.Proxy.html
208/// [`zbus::SignalStream`]: https://docs.rs/zbus/latest/zbus/proxy/struct.SignalStream.html
209/// [`zbus::blocking::SignalIterator`]: https://docs.rs/zbus/latest/zbus/blocking/proxy/struct.SignalIterator.html
210/// [`ObjectPath`]: https://docs.rs/zvariant/latest/zvariant/struct.ObjectPath.html
211/// [dbus_emits_changed_signal]: https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
212#[proc_macro_attribute]
213pub fn proxy(attr: TokenStream, item: TokenStream) -> TokenStream {
214    let args = parse_macro_input!(attr with Punctuated<Meta, Token![,]>::parse_terminated);
215    let input = parse_macro_input!(item as ItemTrait);
216    proxy::expand(args, input)
217        .unwrap_or_else(|err| err.to_compile_error())
218        .into()
219}
220
221/// Attribute macro for implementing a D-Bus interface.
222///
223/// The macro must be applied on an `impl T`. All methods will be exported, either as methods,
224/// properties or signal depending on the item attributes. It will implement the [`Interface`] trait
225/// `for T` on your behalf, to handle the message dispatching and introspection support.
226///
227/// The trait accepts the `interface` attributes:
228///
229/// * `name` - the D-Bus interface name
230///
231/// * `spawn` - Controls the spawning of tasks for method calls. By default, `true`, allowing zbus
232///   to spawn a separate task for each method call. This default behavior can lead to methods being
233///   handled out of their received order, which might not always align with expected or desired
234///   behavior.
235///
236///   - **When True (Default):** Suitable for interfaces where method calls are independent of each
237///     other or can be processed asynchronously without strict ordering. In scenarios where a
238///     client must wait for a reply before making further dependent calls, this default behavior is
239///     appropriate.
240///
241///   - **When False:** Use this setting to ensure methods are handled in the order they are
242///     received, which is crucial for interfaces requiring sequential processing of method calls.
243///     However, care must be taken to avoid making D-Bus method calls from within your interface
244///     methods when this setting is false, as it may lead to deadlocks under certain conditions.
245///
246/// * `proxy` - If specified, a proxy type will also be generated for the interface. This attribute
247///   supports all the [`macro@proxy`]-specific sub-attributes (e.g `gen_async`). The common
248///   sub-attributes (e.g `name`) are automatically forwarded to the [`macro@proxy`] macro.
249///
250/// * `introspection_docs` - whether to include the documentation in the introspection data
251///   (Default: `true`). If your interface is well-known or well-documented, you may want to set
252///   this to `false` to reduce the the size of your binary and D-Bus traffic.
253///
254/// * `crate` - specify the path to the `zbus` crate if it's renamed or re-exported.
255///
256/// The methods accepts the `interface` attributes:
257///
258/// * `name` - override the D-Bus name (pascal case form of the method by default)
259///
260/// * `property` - expose the method as a property. If the method takes an argument, it must be a
261///   setter, with a `set_` prefix. Otherwise, it's a getter. If it may fail, a property method must
262///   return `zbus::fdo::Result`. An additional sub-attribute exists to control the emission of
263///   signals on changes to the property:
264///   * `emits_changed_signal` - specifies how property changes are signaled. Valid values are those
265///     documented in [DBus specifications][dbus_emits_changed_signal]:
266///     * `"true"` - (default) the change signal is always emitted when the property's setter is
267///       called. The value of the property is included in the signal.
268///     * `"invalidates"` - the change signal is emitted, but the value is not included in the
269///       signal.
270///     * `"const"` - the property never changes, thus no signal is ever emitted for it.
271///     * `"false"` - the change signal is not emitted if the property changes. If a property is
272///       write-only, the change signal will not be emitted in this interface.
273///
274/// * `signal` - the method is a "signal". It must be a method declaration (without body). Its code
275///   block will be expanded to emit the signal from the object path associated with the interface
276///   instance. Moreover, `interface` will also generate a trait named `<Interface>Signals` that
277///   provides all the signal methods but without the `SignalEmitter` argument. The macro implements
278///   this trait for two types, `zbus::object_server::InterfaceRef<Interface>` and
279///   `SignalEmitter<'_>`. The former is useful for emitting signals from outside the context of an
280///   interface method and the latter is useful for emitting signals from inside interface methods.
281///
282///   You can call a signal method from a an interface method, or from an [`ObjectServer::with`]
283///   function.
284///
285/// * `out_args` - When returning multiple values from a method, naming the out arguments become
286///   important. You can use `out_args` to specify their names.
287///
288/// * `proxy` - Use this to specify the [`macro@proxy`]-specific method sub-attributes (e.g
289///   `object`). The common sub-attributes (e.g `name`) are automatically forworded to the
290///   [`macro@proxy`] macro. Moreover, you can use `visibility` sub-attribute to specify the
291///   visibility of the generated proxy type(s).
292///
293///   In such case, your method must return a tuple containing
294///   your out arguments, in the same order as passed to `out_args`.
295///
296/// The `struct_return` attribute (from zbus 1.x) is no longer supported. If you want to return a
297/// single structure from a method, declare it to return a tuple containing either a named structure
298/// or a nested tuple.
299///
300/// Note: a `<property_name_in_snake_case>_changed` method is generated for each property: this
301/// method emits the "PropertiesChanged" signal for the associated property. The setter (if it
302/// exists) will automatically call this method. For instance, a property setter named `set_foo`
303/// will be called to set the property "Foo", and will emit the "PropertiesChanged" signal with the
304/// new value for "Foo". Other changes to the "Foo" property can be signaled manually with the
305/// generated `foo_changed` method. In addition, a `<property_name_in_snake_case>_invalidated`
306/// method is also generated that much like `_changed` method, emits a "PropertyChanged" signal
307/// but does not send over the new value of the property along with it. It is usually best to avoid
308/// using this since it will force all interested peers to fetch the new value and hence result in
309/// excess traffic on the bus.
310///
311/// The method arguments support the following `zbus` attributes:
312///
313/// * `object_server` - This marks the method argument to receive a reference to the
314///   [`ObjectServer`] this method was called by.
315/// * `connection` - This marks the method argument to receive a reference to the [`Connection`] on
316///   which the method call was received.
317/// * `header` - This marks the method argument to receive the message header associated with the
318///   D-Bus method call being handled. For property methods, this will be an `Option<Header<'_>>`,
319///   which will be set to `None` if the method is called for reasons other than to respond to an
320///   external property access.
321/// * `signal_emitter` - This marks the method argument to receive a [`SignalEmitter`] instance,
322///   which is needed for emitting signals the easy way.
323///
324/// # Example
325///
326/// ```
327/// # use std::error::Error;
328/// use zbus::interface;
329/// use zbus::{ObjectServer, object_server::SignalEmitter, message::Header};
330///
331/// struct Example {
332///     _some_data: String,
333/// }
334///
335/// #[interface(name = "org.myservice.Example")]
336/// impl Example {
337///     // "Quit" method. A method may throw errors.
338///     async fn quit(
339///         &self,
340///         #[zbus(header)]
341///         hdr: Header<'_>,
342///         #[zbus(signal_emitter)]
343///         emitter: SignalEmitter<'_>,
344///         #[zbus(object_server)]
345///         _server: &ObjectServer,
346///     ) -> zbus::fdo::Result<()> {
347///         let path = hdr.path().unwrap();
348///         let msg = format!("You are leaving me on the {} path?", path);
349///         emitter.bye(&msg).await?;
350///
351///         // Do some asynchronous tasks before quitting..
352///
353///         Ok(())
354///     }
355///
356///     // "TheAnswer" property (note: the "name" attribute), with its associated getter.
357///     // A `the_answer_changed` method has also been generated to emit the
358///     // "PropertiesChanged" signal for this property.
359///     #[zbus(property, name = "TheAnswer")]
360///     fn answer(&self) -> u32 {
361///         2 * 3 * 7
362///     }
363///
364///     // "IFail" property with its associated getter.
365///     // An `i_fail_changed` method has also been generated to emit the
366///     // "PropertiesChanged" signal for this property.
367///     #[zbus(property)]
368///     fn i_fail(&self) -> zbus::fdo::Result<i32> {
369///         Err(zbus::fdo::Error::UnknownProperty("IFail".into()))
370///     }
371///
372///     // "Bye" signal (note: no implementation body).
373///     #[zbus(signal)]
374///     async fn bye(signal_emitter: &SignalEmitter<'_>, message: &str) -> zbus::Result<()>;
375///
376///     #[zbus(out_args("answer", "question"))]
377///     fn meaning_of_life(&self) -> zbus::fdo::Result<(i32, String)> {
378///         Ok((42, String::from("Meaning of life")))
379///     }
380/// }
381///
382/// # Ok::<_, Box<dyn Error + Send + Sync>>(())
383/// ```
384///
385/// See also [`ObjectServer`] documentation to learn how to export an interface over a `Connection`.
386///
387/// [`ObjectServer`]: https://docs.rs/zbus/latest/zbus/object_server/struct.ObjectServer.html
388/// [`ObjectServer::with`]: https://docs.rs/zbus/latest/zbus/object_server/struct.ObjectServer.html#method.with
389/// [`Connection`]: https://docs.rs/zbus/latest/zbus/connection/struct.Connection.html
390/// [`Connection::emit_signal()`]: https://docs.rs/zbus/latest/zbus/connection/struct.Connection.html#method.emit_signal
391/// [`SignalEmitter`]: https://docs.rs/zbus/latest/zbus/object_server/struct.SignalEmitter.html
392/// [`Interface`]: https://docs.rs/zbus/latest/zbus/object_server/trait.Interface.html
393/// [dbus_emits_changed_signal]: https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
394#[proc_macro_attribute]
395pub fn interface(attr: TokenStream, item: TokenStream) -> TokenStream {
396    let args = parse_macro_input!(attr with Punctuated<Meta, Token![,]>::parse_terminated);
397    let input = parse_macro_input!(item as ItemImpl);
398    iface::expand(args, input)
399        .unwrap_or_else(|err| err.to_compile_error())
400        .into()
401}
402
403/// Derive macro for implementing [`zbus::DBusError`] trait.
404///
405/// This macro makes it easy to implement the [`zbus::DBusError`] trait for your custom error type
406/// (currently only enums are supported).
407///
408/// If a special variant marked with the `zbus` attribute is present, `From<zbus::Error>` is
409/// also implemented for your type. This variant can only have a single unnamed field of type
410/// [`zbus::Error`]. This implementation makes it possible for you to declare proxy methods to
411/// directly return this type, rather than [`zbus::Error`].
412///
413/// Each variant (except for the special `zbus` one) can optionally have a (named or unnamed)
414/// `String` field (which is used as the human-readable error description).
415///
416/// The following type-level attributes are supported:
417///
418/// * `prefix` - the D-Bus error name prefix.
419/// * `crate` - specify the path to the `zbus` crate if it's renamed or re-exported.
420///
421/// # Example
422///
423/// ```
424/// use zbus::DBusError;
425///
426/// #[derive(DBusError, Debug)]
427/// #[zbus(prefix = "org.myservice.App")]
428/// enum Error {
429///     #[zbus(error)]
430///     ZBus(zbus::Error),
431///     FileNotFound(String),
432///     OutOfMemory,
433/// }
434/// ```
435///
436/// [`zbus::DBusError`]: https://docs.rs/zbus/latest/zbus/trait.DBusError.html
437/// [`zbus::Error`]: https://docs.rs/zbus/latest/zbus/enum.Error.html
438/// [`zvariant::Type`]: https://docs.rs/zvariant/latest/zvariant/trait.Type.html
439/// [`serde::Serialize`]: https://docs.rs/serde/1.0.132/serde/trait.Serialize.html
440#[proc_macro_derive(DBusError, attributes(zbus))]
441pub fn derive_dbus_error(input: TokenStream) -> TokenStream {
442    let input = parse_macro_input!(input as DeriveInput);
443    error::expand_derive(input)
444        .unwrap_or_else(|err| err.to_compile_error())
445        .into()
446}