### Basic Zbus Service Setup Source: https://github.com/z-galaxy/zbus/blob/main/book/src/service.md Sets up a Zbus session connection, registers a Greeter service, and serves it at a specific path. This is a minimal example to get a service running. ```rust let _connection = connection::Builder::session()?\ .name("org.zbus.MyGreeter")?\ .serve_at("/org/zbus/MyGreeter", Greeter)?\ .build() .await?; ``` -------------------------------- ### Setup Git Hooks Source: https://github.com/z-galaxy/zbus/blob/main/CONTRIBUTING.md Install the repository's git hook scripts to automate checks and formatting before commits. This helps maintain code quality. ```sh cp .githooks/* .git/hooks/ ``` -------------------------------- ### Install cargo-fuzz Source: https://github.com/z-galaxy/zbus/blob/main/zvariant/fuzz/README.md Install the cargo-fuzz tool to enable fuzzing capabilities. ```bash cargo install cargo-fuzz ``` -------------------------------- ### Test D-Bus Service with busctl Source: https://github.com/z-galaxy/zbus/blob/main/zbus/README.md Command-line example to test the 'SayHello' method of the D-Bus service created with zbus. ```bash $ busctl --user call org.zbus.MyGreeter /org/zbus/MyGreeter org.zbus.MyGreeter1 SayHello s "Maria" s "Hello Maria! I have been called 1 times." ``` -------------------------------- ### Install zbus_xmlgen Source: https://github.com/z-galaxy/zbus/blob/main/zbus_xmlgen/README.md Install the zbus_xmlgen tool using cargo. ```shell cargo install zbus_xmlgen ``` -------------------------------- ### Install and Run Fuzz Testing Source: https://github.com/z-galaxy/zbus/blob/main/CLAUDE.md Installs the cargo-fuzz tool and runs fuzz tests for the zvariant crate. Requires a nightly toolchain. ```bash cargo install cargo-fuzz cargo fuzz run --fuzz-dir zvariant/fuzz dbus cargo fuzz run --fuzz-dir zvariant/fuzz --features gvariant gvariant ``` -------------------------------- ### Service activation pitfalls with ObjectServer Source: https://github.com/z-galaxy/zbus/blob/main/book/src/service.md Demonstrates the correct order for setting up interfaces and requesting service names to avoid losing incoming messages during service activation. It highlights the importance of using `connection::Builder` for robust setup. ```rust # use zbus::{connection, interface, Result}; # # # struct Greeter; # # #[interface(name = "org.zbus.MyGreeter1")] ``` -------------------------------- ### Systemd Manager Property Access Example Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md This example shows how to access properties like 'architecture' and 'environment' from the systemd manager service using zbus proxies. It requires the `tokio` runtime. ```rust use zbus::{Connection, proxy, Result}; #[proxy( interface = "org.freedesktop.systemd1.Manager", default_service = "org.freedesktop.systemd1", default_path = "/org/freedesktop/systemd1" )] trait SystemdManager { #[zbus(property)] fn architecture(&self) -> Result; #[zbus(property)] fn environment(&self) -> Result>; } #[tokio::main] async fn main() -> Result<()> { let connection = Connection::system().await?; let proxy = SystemdManagerProxy::new(&connection).await?; println!("Host architecture: {}", proxy.architecture().await?); println!("Environment variables:"); for env in proxy.environment().await? { println!(" {}", env); } Ok(()) } ``` -------------------------------- ### Complete Zbus Service with Properties and Signals Source: https://github.com/z-galaxy/zbus/blob/main/book/src/service.md A comprehensive example demonstrating a Zbus service with methods, properties, signals, and integration with the `event_listener` crate for synchronization. It includes a `say_hello` method, a `greeter_name` property with a setter, and a `greeted_everyone` signal. ```rust use zbus::{object_server::SignalEmitter, connection::Builder, interface, fdo, Result}; use event_listener::{Event, Listener}; struct Greeter { name: String, done: Event, } #[interface(name = "org.zbus.MyGreeter1")] impl Greeter { async fn say_hello(&self, name: &str) -> String { format!("Hello {}!", name) } // Rude! async fn go_away( &self, #[zbus(signal_emitter)] emitter: SignalEmitter<'_>, ) -> fdo::Result<()> { emitter.greeted_everyone().await?; self.done.notify(1); Ok(()) } /// A "GreeterName" property. #[zbus(property)] async fn greeter_name(&self) -> &str { &self.name } /// A setter for the "GreeterName" property. /// /// Additionally, a `greeter_name_changed` method has been generated for you if you need to /// notify listeners that "GreeterName" was updated. It will be automatically called when /// using this setter. #[zbus(property)] async fn set_greeter_name(&mut self, name: String) { self.name = name; } /// A signal; the implementation is provided by the macro. #[zbus(signal)] async fn greeted_everyone(emitter: &SignalEmitter<'_>) -> Result<()>; } // Although we use `tokio` here, you can use any async runtime of choice. #[tokio::main] async fn main() -> Result<()> { let greeter = Greeter { name: "GreeterName".to_string(), done: event_listener::Event::new(), }; let done_listener = greeter.done.listen(); let connection = Builder::session()? .name("org.zbus.MyGreeter")? .serve_at("/org/zbus/MyGreeter", greeter)? .build() .await?; done_listener.wait(); // Let's emit the signal again, just for the fun of it. connection .object_server() .interface("/org/zbus/MyGreeter") .await? .greeted_everyone() .await?; Ok(()) } ``` -------------------------------- ### Geoclue Location Retrieval Example Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md This example shows how to use zbus proxies to interact with Geoclue for location data. It involves setting a desktop ID, subscribing to property changes, and handling location updates. Requires the `tokio` runtime. ```rust use zbus::{zvariant::ObjectPath, proxy, Connection, Result}; use futures_util::stream::StreamExt; #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Manager", default_path = "/org/freedesktop/GeoClue2/Manager" )] trait Manager { #[zbus(object = "Client")] fn get_client(&self); } #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Client" )] trait Client { fn start(&self) -> Result<()>; fn stop(&self) -> Result<()>; #[zbus(property)] fn set_desktop_id(&mut self, id: &str) -> Result<()>; #[zbus(signal)] fn location_updated(&self, old: ObjectPath<'_>, new: ObjectPath<'_>) -> Result<()>; } #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Location" )] trait Location { #[zbus(property)] fn latitude(&self) -> Result; #[zbus(property)] fn longitude(&self) -> Result; } // Although we use `tokio` here, you can use any async runtime of choice. #[tokio::main] async fn main() -> Result<()> { let conn = Connection::system().await?; let manager = ManagerProxy::new(&conn).await?; let mut client = manager.get_client().await?; // Gotta do this, sorry! client.set_desktop_id("org.freedesktop.zbus").await?; let props = zbus::fdo::PropertiesProxy::builder(&conn) .destination("org.freedesktop.GeoClue2")? .path(client.inner().path())? .build() .await?; let mut props_changed = props.receive_properties_changed().await?; let mut location_updated = client.receive_location_updated().await?; client.start().await?; futures_util::try_join!( async { while let Some(signal) = props_changed.next().await { let args = signal.args()?; for (name, value) in args.changed_properties().iter() { println!("{}.{} changed to `{:?}`", args.interface_name(), name, value); } } Ok::<(), zbus::Error>(()) }, async { while let Some(signal) = location_updated.next().await { let args = signal.args()?; let location = LocationProxy::builder(&conn) .path(args.new())? .build() .await?; println!( "Latitude: {}\nLongitude: {}", location.latitude().await?, location.longitude().await?, ); } // No need to specify type of Result each time Ok(()) } )?; Ok(()) } ``` -------------------------------- ### Create a Simple D-Bus Client in Rust Source: https://github.com/z-galaxy/zbus/blob/main/README.md Implement a D-Bus client to call methods on a remote service. This example connects to the session bus and uses a proxy to call the SayHello method. ```rust use zbus::{Connection, Result, proxy}; #[proxy( interface = "org.zbus.MyGreeter1", default_service = "org.zbus.MyGreeter", default_path = "/org/zbus/MyGreeter" )] trait MyGreeter { async fn say_hello(&self, name: &str) -> Result; } // Although we use `tokio` here, you can use any async runtime of choice. #[tokio::main] async fn main() -> Result<()> { let connection = Connection::session().await?; // `proxy` macro creates `MyGreeterProxy` based on `Notifications` trait. let proxy = MyGreeterProxy::new(&connection).await?; let reply = proxy.say_hello("Maria").await?; println!("{reply}"); Ok(()) } ``` -------------------------------- ### Configure zbus with Tokio feature Source: https://github.com/z-galaxy/zbus/blob/main/zbus/README.md Example Cargo.toml snippet to enable tight integration with the Tokio async runtime. This avoids zbus launching its own threads and executor management. ```toml # Sample Cargo.toml snippet. [dependencies] # Also disable the default `async-io` feature to avoid unused dependencies. zbus = { version = "5", default-features = false, features = ["tokio"] } ``` -------------------------------- ### Systemd Unit Job Signal Handling Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md Example of using a trait-derived proxy to subscribe to and handle the `JobNew` signal from the `org.freedesktop.systemd1.Manager` D-Bus interface. This demonstrates the stream-based API for receiving signals. ```APIDOC ### Signals Signals are like methods, except they don't expect a reply. They are typically emitted by services to notify interested peers of any changes to the state of the service. zbus provides you a [`Stream`]-based API for receiving signals. Let's look at this API in action, with an example where we monitor started systemd units. ```rust,no_run # // NOTE: When changing this, please also keep `zbus/examples/watch-systemd-jobs.rs` in sync. use futures_util::stream::StreamExt; use zbus::{zvariant::OwnedObjectPath, proxy, Connection}; # fn main() { # async_io::block_on(watch_systemd_jobs()).expect("Error listening to signal"); # } #[proxy( default_service = "org.freedesktop.systemd1", default_path = "/org/freedesktop/systemd1", interface = "org.freedesktop.systemd1.Manager" )] trait Systemd1Manager { // Defines signature for D-Bus signal named `JobNew` #[zbus(signal)] fn job_new(&self, id: u32, job: OwnedObjectPath, unit: String) -> zbus::Result<()>; } async fn watch_systemd_jobs() -> zbus::Result<()> { let connection = Connection::system().await?; // `Systemd1ManagerProxy` is generated from `Systemd1Manager` trait let systemd_proxy = Systemd1ManagerProxy::new(&connection).await?; // Method `receive_job_new` is generated from `job_new` signal let mut new_jobs_stream = systemd_proxy.receive_job_new().await?; while let Some(msg) = new_jobs_stream.next().await { // struct `JobNewArgs` is generated from `job_new` signal function arguments let args: JobNewArgs = msg.args().expect("Error parsing message"); println!( "JobNew received: unit={} id={} path={}", args.unit, args.id, args.job ); } panic!("Stream ended unexpectedly"); } ``` ``` -------------------------------- ### Introspection of Complete Zbus Service Source: https://github.com/z-galaxy/zbus/blob/main/book/src/service.md Displays the introspection result for the more complete Zbus Greeter service example, highlighting the defined methods, properties, and signals. ```bash $ busctl --user introspect org.zbus.MyGreeter /org/zbus/MyGreeter NAME TYPE SIGNATURE RESULT/VALUE FLAGS [...] org.zbus.MyGreeter1 interface - - - .GoAway method - - - .SayHello method s s - .GreeterName property s "GreeterName" emits-change writable .GreetedEveryone signal - - - ``` -------------------------------- ### Check Cross-Platform Compatibility Source: https://github.com/z-galaxy/zbus/blob/main/CLAUDE.md Compiles the code for different target platforms to check for cross-platform compatibility issues. Requires appropriate target toolchains to be installed. ```bash cargo check --target x86_64-pc-windows-gnu cargo check --target x86_64-apple-darwin cargo check --target x86_64-unknown-freebsd ``` -------------------------------- ### Notifications Proxy Call Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md Example of using a trait-derived proxy to call the `org.freedesktop.Notifications.Notify` D-Bus method. This demonstrates asynchronous proxy creation and method invocation. ```APIDOC ## Trait-derived proxy call A trait declaration `T` with a `proxy` attribute will have a derived `TProxy` and `TProxyBlocking` (see [chapter on "blocking"][cob] for more information on that) implemented thanks to procedural macros. The trait methods will have respective `impl` methods wrapping the D-Bus calls: ```rust,no_run use std::collections::HashMap; use std::error::Error; use zbus::{zvariant::Value, proxy, Connection}; #[proxy( default_service = "org.freedesktop.Notifications", default_path = "/org/freedesktop/Notifications" )] trait Notifications { /// Call the org.freedesktop.Notifications.Notify D-Bus method fn notify(&self, app_name: &str, replaces_id: u32, app_icon: &str, summary: &str, body: &str, actions: &[&str], hints: HashMap<&str, &Value<'_>>, expire_timeout: i32) -> zbus::Result; } // Although we use `tokio` here, you can use any async runtime of choice. #[tokio::main] async fn main() -> Result<(), Box> { let connection = Connection::session().await?; let proxy = NotificationsProxy::new(&connection).await?; let reply = proxy.notify( "my-app", 0, "dialog-information", "A summary", "Some body", &[], HashMap::new(), 5000, ).await?; dbg!(reply); Ok(()) } ``` A `TProxy` and `TProxyBlocking` has a few associated methods, such as `new(connection)`, using the default associated service name and object path, and an associated builder if you need to specify something different. This should help to avoid the kind of mistakes we saw earlier. It's also a bit easier to use, thanks to Rust type inference. This makes it also possible to have higher-level types, they fit more naturally with the rest of the code. You can further document the D-Bus API or provide additional helpers. > **Note** > > For simple transient cases like the one above, you may find the [blocking API][cob] very > convenient to use. ``` -------------------------------- ### Struct with Optional Fields and Default Trait Source: https://github.com/z-galaxy/zbus/blob/main/book/src/faq.md This example demonstrates using `serde` with `#[serde(default)]` and the `Default` trait for a struct with optional fields. It ensures optional fields are handled correctly during serialization and deserialization, especially when they might be absent. ```rust # use zbus::zvariant::{Type, as_value::{self, optional}}; # use serde::{Deserialize, Serialize}; # #[derive(Default, Deserialize, Serialize, Type)] #[zvariant(signature = "dict")] #[serde(default)] pub struct Dictionary { #[serde(with = "as_value")] field1: u16, #[serde(with = "optional", skip_serializing_if = "Option::is_none")] optional_field1: Option, #[serde(with = "optional", skip_serializing_if = "Option::is_none")] optional_field2: Option, } ``` -------------------------------- ### Watch for Property Changes with zbus Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md Use the `receive__changed()` stream API to be notified of property changes. This example demonstrates watching for changes to the `LogLevel` property of the systemd manager. ```rust use zbus::{Connection, proxy, Result}; use futures_util::stream::StreamExt; #[tokio::main] async fn main() -> Result<()> { #[proxy( interface = "org.freedesktop.systemd1.Manager", default_service = "org.freedesktop.systemd1", default_path = "/org/freedesktop/systemd1" )] trait SystemdManager { #[zbus(property)] fn log_level(&self) -> Result; } let connection = Connection::system().await?; let proxy = SystemdManagerProxy::new(&connection).await?; let mut stream = proxy.receive_log_level_changed().await; while let Some(v) = stream.next().await { println!("LogLevel changed: {:?}", v.get().await); } Ok(()) } ``` -------------------------------- ### Geoclue Location Retrieval Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md An advanced example demonstrating how to retrieve location data using Geoclue via zbus. It shows how to handle signals for property changes and location updates. ```APIDOC ## Geoclue Location Retrieval Example ### Description This example shows how to use zbus to interact with the Geoclue2 D-Bus service to get the user's current location. It involves setting up proxies for the Manager, Client, and Location interfaces, handling property changes, and subscribing to location updates. ### Interfaces Used - `org.freedesktop.GeoClue2.Manager` - `org.freedesktop.GeoClue2.Client` - `org.freedesktop.GeoClue2.Location` - `org.freedesktop.DBus.Properties` ### Key Operations - `ManagerProxy::get_client()`: Retrieves a proxy for the Geoclue client. - `ClientProxy::set_desktop_id()`: Sets the desktop ID for the client. - `ClientProxy::start()`: Starts the location service. - `ClientProxy::stop()`: Stops the location service. - `LocationProxy::latitude()`: Gets the latitude property. - `LocationProxy::longitude()`: Gets the longitude property. - `PropertiesProxy::receive_properties_changed()`: Subscribes to property change signals. - `ClientProxy::receive_location_updated()`: Subscribes to location update signals. ### Example Code ```rust,no_run use zbus::{zvariant::ObjectPath, proxy, Connection, Result}; use futures_util::stream::StreamExt; #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Manager", default_path = "/org/freedesktop/GeoClue2/Manager" )] trait Manager { #[zbus(object = "Client")] fn get_client(&self); } #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Client" )] trait Client { fn start(&self) -> Result<()>; fn stop(&self) -> Result<()>; #[zbus(property)] fn set_desktop_id(&mut self, id: &str) -> Result<()>; #[zbus(signal)] fn location_updated(&self, old: ObjectPath<'_>, new: ObjectPath<'_>) -> Result<()>; } #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Location" )] trait Location { #[zbus(property)] fn latitude(&self) -> Result; #[zbus(property)] fn longitude(&self) -> Result; } #[tokio::main] async fn main() -> Result<()> { let conn = Connection::system().await?; let manager = ManagerProxy::new(&conn).await?; let mut client = manager.get_client().await?; client.set_desktop_id("org.freedesktop.zbus").await?; let props = zbus::fdo::PropertiesProxy::builder(&conn) .destination("org.freedesktop.GeoClue2")? .path(client.inner().path())? .build() .await?; let mut props_changed = props.receive_properties_changed().await?; let mut location_updated = client.receive_location_updated().await?; client.start().await?; futures_util::try_join!( async { while let Some(signal) = props_changed.next().await { let args = signal.args()?; for (name, value) in args.changed_properties().iter() { println!("{}.{} changed to `{:?}`", args.interface_name(), name, value); } } Ok::<(), zbus::Error>(()) }, async { while let Some(signal) = location_updated.next().await { let args = signal.args()?; let location = LocationProxy::builder(&conn) .path(args.new())? .build() .await?; println!( "Latitude: {}\nLongitude: 1", location.latitude().await?, location.longitude().await?, ); } Ok(()) } )?; Ok(()) } ``` ``` -------------------------------- ### Generate D-Bus Trait from XML Interface Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md This Rust code demonstrates how to define a D-Bus interface using the `#[proxy]` attribute, specifying the interface name, default service, and default path. It includes an example of a method signature for `get_server_information`. ```rust /// The server's version number. pub version: String, /// The specification version the server is compliant with. pub spec_version: String, } #[proxy( interface = "org.freedesktop.Notifications", default_service = "org.freedesktop.Notifications", default_path= "/org/freedesktop/Notifications", )] trait Notifications { /// Get server information. /// /// This message returns the information on the server. fn get_server_information(&self) -> zbus::Result; } ``` -------------------------------- ### Build mdbook Documentation Source: https://github.com/z-galaxy/zbus/blob/main/CLAUDE.md Builds the project's main documentation website using mdbook. Requires navigating to the book directory first. ```bash cd book && mdbook build ``` -------------------------------- ### Create a D-Bus Client with zbus Source: https://github.com/z-galaxy/zbus/blob/main/zbus/README.md Demonstrates how to create a D-Bus client to call the 'SayHello' method on the 'MyGreeter' service. This requires the service to be running. ```rust use zbus::{Connection, Result, proxy}; #[proxy( interface = "org.zbus.MyGreeter1", default_service = "org.zbus.MyGreeter", default_path = "/org/zbus/MyGreeter" )] trait MyGreeter { async fn say_hello(&self, name: &str) -> Result; } // Although we use `tokio` here, you can use any async runtime of choice. #[tokio::main] async fn main() -> Result<()> { let connection = Connection::session().await?; // `proxy` macro creates `MyGreaterProxy` based on `MyGreeter` trait. let proxy = MyGreeterProxy::new(&connection).await?; let reply = proxy.say_hello("Maria").await?; println!("{reply}"); Ok(()) } ``` -------------------------------- ### Create a D-Bus Service with zbus Source: https://github.com/z-galaxy/zbus/blob/main/zbus/README.md Demonstrates how to create a D-Bus service that exposes a 'SayHello' method. Ensure a D-Bus session bus is running and the DBUS_SESSION_BUS_ADDRESS environment variable is set. ```rust use std::{error::Error, future::pending}; use zbus::{connection, interface}; struct Greeter { count: u64 } #[interface(name = "org.zbus.MyGreeter1")] impl Greeter { // Can be `async` as well. fn say_hello(&mut self, name: &str) -> String { self.count += 1; format!("Hello {}! I have been called {} times.", name, self.count) } } // Although we use `tokio` here, you can use any async runtime of choice. #[tokio::main] async fn main() -> Result<(), Box> { let greeter = Greeter { count: 0 }; let _conn = connection::Builder::session()? .name("org.zbus.MyGreeter")? .serve_at("/org/zbus/MyGreeter", greeter)? .build() .await?; // Do other things or go to wait forever pending::<()>().await; Ok(()) } ``` -------------------------------- ### D-Bus Introspection XML Output Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md Example output of the D-Bus introspection XML for the notification service. This XML defines the methods, signals, and properties of the D-Bus interface. ```xml ``` -------------------------------- ### Run Full Test Suite Source: https://github.com/z-galaxy/zbus/blob/main/CONTRIBUTING.md Execute the complete test suite, including documentation tests and compile-time tests. Ensure all tests pass before submitting changes. ```sh cargo test --all-features ``` -------------------------------- ### Build Documentation for Crates Source: https://github.com/z-galaxy/zbus/blob/main/CLAUDE.md Generates documentation for specified crates, including all features. Useful for reviewing API documentation. ```bash cargo doc --all-features -p zbus cargo doc --all-features -p zvariant ``` -------------------------------- ### Greeter Service Interface Source: https://github.com/z-galaxy/zbus/blob/main/book/src/service.md This section details the methods and properties exposed by the Greeter service. ```APIDOC ## org.zbus.MyGreeter1 ### Description Interface for the Greeter service. ### Methods #### SayHello - **Description**: Greets a given name. - **Signature**: s -> s - **Parameters**: - name (s) - The name to greet. - **Return Value**: - (s) - The greeting string. #### GoAway - **Description**: Signals that the greeter is going away. - **Signature**: - - **Parameters**: None. - **Return Value**: None. ### Properties #### GreeterName - **Description**: The name of the greeter. - **Signature**: s - **Access**: writable - **Emits Change**: Yes ### Signals #### GreetedEveryone - **Description**: Emitted when the greeter has greeted everyone. ``` -------------------------------- ### Serialization and Deserialization with zvariant Source: https://github.com/z-galaxy/zbus/blob/main/zvariant/README.md Demonstrates serialization and deserialization of various data types including primitives, strings, tuples, vectors, and HashMaps using zvariant's to_bytes function and serde. Requires a serialized::Context instance. ```rust use std::collections::HashMap; use zvariant::{serialized::Context, to_bytes, Type, LE}; use serde::{Deserialize, Serialize}; // All serialization and deserialization API, needs a context. let ctxt = Context::new_dbus(LE, 0); // You can also use the more efficient GVariant format: // let ctxt = Context::new_gvariant(LE, 0); // i16 let encoded = to_bytes(ctxt, &42i16).unwrap(); let decoded: i16 = encoded.deserialize().unwrap().0; assert_eq!(decoded, 42); // strings let encoded = to_bytes(ctxt, &"hello").unwrap(); let decoded: &str = encoded.deserialize().unwrap().0; assert_eq!(decoded, "hello"); // tuples let t = ("hello", 42i32, true); let encoded = to_bytes(ctxt, &t).unwrap(); let decoded: (&str, i32, bool) = encoded.deserialize().unwrap().0; assert_eq!(decoded, t); // Vec let v = vec!["hello", "world!"]; let encoded = to_bytes(ctxt, &v).unwrap(); let decoded: Vec<&str> = encoded.deserialize().unwrap().0; assert_eq!(decoded, v); // Dictionary let mut map: HashMap = HashMap::new(); map.insert(1, "123"); map.insert(2, "456"); let encoded = to_bytes(ctxt, &map).unwrap(); let decoded: HashMap = encoded.deserialize().unwrap().0; assert_eq!(decoded[&1], "123"); assert_eq!(decoded[&2], "456"); ``` -------------------------------- ### Run Benchmarks Source: https://github.com/z-galaxy/zbus/blob/main/CLAUDE.md Executes the performance benchmarks defined in the project. Useful for performance analysis. ```bash cargo bench ``` -------------------------------- ### Blocking Client and Signal Handling Source: https://github.com/z-galaxy/zbus/blob/main/book/src/blocking.md Demonstrates creating a blocking client and handling signals using the blocking API. Note that signal reception for blocking APIs implements `std::iter::Iterator`. ```rust use zbus::{blocking::Connection, zvariant::ObjectPath, proxy, Result}; #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Manager", default_path = "/org/freedesktop/GeoClue2/Manager" )] trait Manager { #[zbus(object = "Client")] /// The method normally returns an `ObjectPath`. /// With the object attribute, we can make it return a `ClientProxy` directly. fn get_client(&self); } #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Client" )] trait Client { fn start(&self) -> Result<()>; fn stop(&self) -> Result<()>; #[zbus(property)] fn set_desktop_id(&mut self, id: &str) -> Result<()>; #[zbus(signal)] fn location_updated(&self, old: ObjectPath<'_>, new: ObjectPath<'_>) -> Result<()>; } #[proxy( default_service = "org.freedesktop.GeoClue2", interface = "org.freedesktop.GeoClue2.Location" )] trait Location { #[zbus(property)] fn latitude(&self) -> Result; #[zbus(property)] fn longitude(&self) -> Result; } let conn = Connection::system().unwrap(); let manager = ManagerProxyBlocking::new(&conn).unwrap(); let mut client = manager.get_client().unwrap(); // Gotta do this, sorry! client.set_desktop_id("org.freedesktop.zbus").unwrap(); let mut location_updated = client.receive_location_updated().unwrap(); client.start().unwrap(); // Wait for the signal. let signal = location_updated.next().unwrap(); let args = signal.args().unwrap(); let location = LocationProxyBlocking::builder(&conn) .path(args.new()) .unwrap() .build() .unwrap(); println!( "Latitude: {}\nLongitude:જી", location.latitude().unwrap(), location.longitude().unwrap(), ); ``` -------------------------------- ### Implement a Blocking zbus Server Source: https://github.com/z-galaxy/zbus/blob/main/book/src/blocking.md This Rust code defines a Greeter service with methods and properties, and sets it up to run on a blocking zbus connection. It includes signal handling for property changes and a mechanism to shut down the server. ```rust use zbus::{blocking::connection, interface, fdo, object_server::SignalEmitter}; use event_listener::{Event, Listener}; struct Greeter { name: String, done: Event, } #[interface(name = "org.zbus.MyGreeter1")] impl Greeter { fn say_hello(&self, name: &str) -> String { format!("Hello {}!", name) } // Rude! async fn go_away( &self, #[zbus(signal_emitter)] emitter: SignalEmitter<'_>, ) -> fdo::Result<()> { emitter.greeted_everyone().await?; self.done.notify(1); Ok(()) } /// A "GreeterName" property. #[zbus(property)] fn greeter_name(&self) -> &str { &self.name } /// A setter for the "GreeterName" property. /// /// Additionally, a `greeter_name_changed` method has been generated for you if you need to /// notify listeners that "GreeterName" was updated. It will be automatically called when /// using this setter. #[zbus(property)] fn set_greeter_name(&mut self, name: String) { self.name = name; } /// A signal; the implementation is provided by the macro. #[zbus(signal)] async fn greeted_everyone(emitter: &SignalEmitter<'_>) -> zbus::Result<()>; } fn main() -> Result<(), Box> { let greeter = Greeter { name: "GreeterName".to_string(), done: event_listener::Event::new(), }; let done_listener = greeter.done.listen(); let _handle = connection::Builder::session()? .name("org.zbus.MyGreeter")? .serve_at("/org/zbus/MyGreeter", greeter)? .build()?; done_listener.wait(); Ok(()) } ``` -------------------------------- ### Define Property Getter with #[proxy] Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md This snippet demonstrates how to define a getter for a D-Bus property using the `#[zbus(property)]` attribute within a `#[proxy]` trait. The `state()` method will translate to a "State" property Get call. ```rust use zbus::{proxy, Result}; #[proxy] trait MyInterface { #[zbus(property)] fn state(&self) -> Result; } ``` -------------------------------- ### Generate Code from XML File Source: https://github.com/z-galaxy/zbus/blob/main/zbus_xmlgen/README.md Generate Rust code from a local D-Bus XML interface description file. Use '-' for stdin. ```shell zbus-xmlgen file interface.xml ``` -------------------------------- ### Implement a D-Bus interface with ObjectServer Source: https://github.com/z-galaxy/zbus/blob/main/book/src/service.md Uses the `ObjectServer` and `interface` macro to automatically handle D-Bus method calls and introspection. This simplifies service implementation by abstracting message dispatching. ```rust use zbus::{Connection, interface, Result}; struct Greeter; #[interface(name = "org.zbus.MyGreeter1")] impl Greeter { async fn say_hello(&self, name: &str) -> String { format!("Hello {}!", name) } } // Although we use `tokio` here, you can use any async runtime of choice. #[tokio::main] async fn main() -> Result<()> { let connection = Connection::session().await?; // setup the object server connection .object_server() .at("/org/zbus/MyGreeter", Greeter) .await?; // before requesting the name connection .request_name("org.zbus.MyGreeter") .await?; loop { // do something else, wait forever or timeout here: // handling D-Bus messages is done in the background std::future::pending::<()>().await; } } ``` -------------------------------- ### Low-level D-Bus call with zbus::Connection Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md Shows how to make a low-level D-Bus method call to the notification service using `zbus::Connection::call_method`. This approach handles message signatures automatically but requires careful argument management. ```rust use std::collections::HashMap; use std::error::Error; use zbus::{zvariant::Value, Connection}; // Although we use `tokio` here, you can use any async runtime of choice. #[tokio::main] async fn main() -> Result<(), Box> { let connection = Connection::session().await?; let m = connection.call_method( Some("org.freedesktop.Notifications"), "/org/freedesktop/Notifications", Some("org.freedesktop.Notifications"), "Notify", &("my-app", 0u32, "dialog-information", "A summary", "Some body", vec!["", 0], HashMap::<&str, &Value>::new(), 5000), ).await?; let reply: u32 = m.body().deserialize().unwrap(); dbg!(reply); Ok(()) } ``` -------------------------------- ### Peer-to-peer connection on Unix Source: https://github.com/z-galaxy/zbus/blob/main/book/src/connection.md Establishes a bus-less peer-to-peer connection on Unix using `UnixStream`. Requires the `p2p` cargo feature of `zbus` to be enabled. The `p2p` and `server` methods are available when this feature is enabled. ```rust # #[tokio::main] # async fn main() -> zbus::Result<()> # { # #[cfg(unix)] # { #[cfg(not(feature = "tokio"))] use std::os::unix::net::UnixStream; #[cfg(feature = "tokio")] use tokio::net::UnixStream; use zbus::{connection::Builder, Guid}; let guid = Guid::generate(); let (p0, p1) = UnixStream::pair().unwrap(); #[allow(unused)] let (client_conn, server_conn) = futures_util::try_join!( // Client Builder::unix_stream(p0).p2p().build(), // Server Builder::unix_stream(p1).server(guid)?.p2p().build(), )?; # } # # Ok(()) # } ``` -------------------------------- ### Receive D-Bus Signals with Streams Source: https://github.com/z-galaxy/zbus/blob/main/book/src/client.md Sets up a stream to receive `JobNew` signals from the `org.freedesktop.systemd1.Manager` D-Bus interface. It uses a generated proxy and signal receiver to process incoming signal messages. ```rust # // NOTE: When changing this, please also keep `zbus/examples/watch-systemd-jobs.rs` in sync. use futures_util::stream::StreamExt; use zbus::{zvariant::OwnedObjectPath, proxy, Connection}; # fn main() { # async_io::block_on(watch_systemd_jobs()).expect("Error listening to signal"); # } #[proxy( default_service = "org.freedesktop.systemd1", default_path = "/org/freedesktop/systemd1", interface = "org.freedesktop.systemd1.Manager" )] trait Systemd1Manager { // Defines signature for D-Bus signal named `JobNew` #[zbus(signal)] fn job_new(&self, id: u32, job: OwnedObjectPath, unit: String) -> zbus::Result<()>; } async fn watch_systemd_jobs() -> zbus::Result<()> { let connection = Connection::system().await?; // `Systemd1ManagerProxy` is generated from `Systemd1Manager` trait let systemd_proxy = Systemd1ManagerProxy::new(&connection).await?; // Method `receive_job_new` is generated from `job_new` signal let mut new_jobs_stream = systemd_proxy.receive_job_new().await?; while let Some(msg) = new_jobs_stream.next().await { // struct `JobNewArgs` is generated from `job_new` signal function arguments let args: JobNewArgs = msg.args().expect("Error parsing message"); println!( "JobNew received: unit={} id={} path={}", args.unit, args.id, args.job ); } panic!("Stream ended unexpectedly"); } ``` -------------------------------- ### Generate Client-Side Proxy with `interface` Macro Source: https://github.com/z-galaxy/zbus/blob/main/book/src/service.md Instructs the `interface` macro to generate client-side proxy code using the `proxy` attribute. Common attributes are forwarded to the `proxy` macro. ```rust use zbus::interface; struct Greeter { name: String } #[interface( name = "org.zbus.MyGreeter.WithProxy", // Specifying the `proxy` attribute instructs `interface` to generate the // client-side proxy. You can specify proxy-specific attributes // (e.g `gen_blocking) here. All the attributes that are common between // `proxy` and `interface` macros (e.g `name`) are automtically forwarded to // the `proxy` macro. proxy( gen_blocking = false, default_path = "/org/zbus/MyGreeter/WithProxy", default_service = "org.zbus.MyGreeter.WithProxy", ), )] impl Greeter { #[zbus(property)] async fn greeter_name(&self) -> String { self.name.clone() } #[zbus(proxy(no_reply))] async fn whatever(&self) { println!("Whatever!"); } } # #[tokio::main] # async fn main() -> zbus::Result<()> { let greeter = Greeter { name: "GreeterName".to_string() }; let connection = zbus::connection::Builder::session()? .name("org.zbus.MyGreeter.WithProxy")? .serve_at("/org/zbus/MyGreeter/WithProxy", greeter)? .build() .await?; let proxy = GreeterProxy::new(&connection).await?; assert_eq!(proxy.greeter_name().await?, "GreeterName"); proxy.whatever().await?; # Ok(()) # } ``` -------------------------------- ### Format Code Source: https://github.com/z-galaxy/zbus/blob/main/CONTRIBUTING.md Apply code formatting to the entire project using the nightly toolchain. This ensures consistent code style across the project. ```sh cargo +nightly fmt --all ```