Skip to content

Commit

Permalink
Merge pull request #873 from zeenix/book-improvements-updates
Browse files Browse the repository at this point in the history
A bunch of improvements and fixes to book
  • Loading branch information
zeenix authored Jun 29, 2024
2 parents 80c25ec + 9e443e3 commit 0ece0f0
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 16 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ jobs:
mkdir mdbook
curl -sSL $url | tar -xz --directory=./mdbook
echo `pwd`/mdbook >> $GITHUB_PATH
- name: Install latest mdbook-toc
run: |
tag=$(curl 'https://api.github.com/repos/badboy/mdbook-toc/releases/latest' | jq -r '.tag_name')
url="https://github.com/badboy/mdbook-toc/releases/download/${tag}/mdbook-toc-${tag}-x86_64-unknown-linux-gnu.tar.gz"
mkdir mdbook-toc
curl -sSL $url | tar -xz --directory=./mdbook-toc
echo `pwd`/mdbook-toc >> $GITHUB_PATH
- name: Build Books
run: |
mdbook build book
Expand Down
14 changes: 10 additions & 4 deletions book/book.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
[book]
authors = ["Marc-André Lureau"]
authors = ["Marc-André Lureau", "Zeeshan Ali Khan"]
language = "en"
multilingual = false
src = "src"
title = "zbus: D-Bus for Rust made easy"

[rust]
edition = "2018"
edition = "2021"

[output.html]
default-theme = "Rust"
curly-quotes = true
smart-punctuation = true
git-repository-url = "https://github.com/dbus2/zbus"
git-repository-icon = "fa-gitlab"
edit-url-template = "https://github.com/dbus2/zbus/edit/main/book/{path}"
git-repository-icon = "fa-github"
no-section-label = true

[preprocessor.toc]
command = "mdbook-toc"
renderer = ["html"]
2 changes: 1 addition & 1 deletion book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- [Some D-Bus concepts](concepts.md)
- [Establishing connections](connection.md)
- [Writing a client proxy](client.md)
- [Writing a server interface](server.md)
- [Writing a service interface](service.md)
- [Blocking API](blocking.md)
- [FAQ](faq.md)

Expand Down
2 changes: 2 additions & 0 deletions book/src/blocking.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Blocking API

<!-- toc -->

While zbus API being primarily asynchronous (since 2.0) is a great thing, it could easily feel
daunting for simple use cases. Not to worry! In the spirit of "ease" being a primary goal of zbus,
it provides blocking wrapper types, under the [blocking module].
Expand Down
2 changes: 2 additions & 0 deletions book/src/client.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Writing a client proxy

<!-- toc -->

In this chapter, we are going to see how to make low-level D-Bus method calls. Then we are going to
dive in, and derive from a trait to make a convenient Rust binding. Finally, we will learn about
*xmlgen*, a tool to help us generate a boilerplate trait from the XML of an introspected service.
Expand Down
6 changes: 4 additions & 2 deletions book/src/concepts.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Some D-Bus concepts to help newcomers

<!-- toc -->

## Bus

A D-Bus "bus" is a kind of server that handles several connections in a bus-topology fashion. As
such, it relays messages between connected endpoints, and allows to discover endpoints or sending
A D-Bus "bus" is a server that handles several connections in a bus-topology fashion. As such, it
relays messages between connected endpoints, and allows to discover endpoints or sending
broadcast messages (signals).

Typically, a Linux system has a system bus, and a session bus. The latter is per-user. It is also
Expand Down
2 changes: 2 additions & 0 deletions book/src/connection.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Establishing a connection

<!-- toc -->

The first thing you will have to do is to connect to a D-Bus bus or to a D-Bus peer. This is the
entry point of the zbus API.

Expand Down
79 changes: 78 additions & 1 deletion book/src/faq.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# FAQ

<!-- toc -->

## How to use a struct as a dictionary?

Since the use of a dictionary, specifically one with strings as keys and variants as value (i-e
Expand Down Expand Up @@ -94,7 +96,7 @@ A common issue might arise when using a zbus proxy is that your proxy's property
updating. This is due to zbus' default caching policy, which updates the value of a property only
when a change is signaled, primarily to minimize latency and optimize client request performance.
By default, if your service does not emit change notifications, the property values will not
update accordingly.
update accordingly.

However, you can disabling caching for specific properties:

Expand Down Expand Up @@ -131,6 +133,7 @@ The idea here is to represent `None` case with 0 elements (empty array) and the
element. `zvariant` and `zbus` provide `option-as-array` Cargo feature, which when enabled, allows
the (de)serialization of `Option<T>`. Unlike the previous solution, this solution can be used with
all types. However, it does come with some caveats and limitations:

1. Since the D-Bus type signature does not provide any hints about the array being in fact a
nullable type, this can be confusing for users of generic tools like [`d-feet`]. It is therefore
highly recommended that service authors document each use of `Option<T>` in their D-Bus
Expand All @@ -147,6 +150,77 @@ enabled.

**Note**: We hope to be able to remove #2 and #4, once [specialization] lands in stable Rust.

## How do enums work?

By default, `zvariant` encodes an unit-type enum as a `u32`, denoting the variant index. Other enums
are encoded as a structure whose first field is the variant index and the second one are the
variant's field(s). The only caveat here is that all variants must have the same number and types
of fields. Names of fields don't matter though. You can make use of [`Value`] or [`OwnedValue`] if you want to encode different data in different fields. Here is a simple example:

```rust,noplayground
use zbus::zvariant::{serialized::Context, to_bytes, Type, LE};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Type, PartialEq, Debug)]
enum Enum<'s> {
Variant1 { field1: u16, field2: i64, field3: &'s str },
Variant2(u16, i64, &'s str),
Variant3 { f1: u16, f2: i64, f3: &'s str },
}
let e = Enum::Variant3 {
f1: 42,
f2: i64::max_value(),
f3: "hello",
};
let ctxt = Context::new_dbus(LE, 0);
let encoded = to_bytes(ctxt, &e).unwrap();
let decoded: Enum = encoded.deserialize().unwrap().0;
assert_eq!(decoded, e);
```

Enum encoding can be adjusted by using the [`serde_repr`] crate and by annotating the representation of the enum with `repr`:

```rust,noplayground
use zbus::zvariant::{serialized::Context, to_bytes, Type, LE};
use serde_repr::{Serialize_repr, Deserialize_repr};
#[derive(Deserialize_repr, Serialize_repr, Type, PartialEq, Debug)]
#[repr(u8)]
enum UnitEnum {
Variant1,
Variant2,
Variant3,
}
let ctxt = Context::new_dbus(LE, 0);
let encoded = to_bytes(ctxt, &UnitEnum::Variant2).unwrap();
let e: UnitEnum = encoded.deserialize().unwrap().0;
assert_eq!(e, UnitEnum::Variant2);
```

Unit enums can also be (de)serialized as strings:

```rust,noplayground
use zbus::zvariant::{serialized::Context, to_bytes, Type, LE};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Type, PartialEq, Debug)]
#[zvariant(signature = "s")]
enum StrEnum {
Variant1,
Variant2,
Variant3,
}
let ctxt = Context::new_dbus(LE, 0);
let encoded = to_bytes(ctxt, &StrEnum::Variant2).unwrap();
let e: StrEnum = encoded.deserialize().unwrap().0;
assert_eq!(e, StrEnum::Variant2);
let s: &str = encoded.deserialize().unwrap().0;
assert_eq!(s, "Variant2");
```

[`proxy::Builder::uncached_properties`]: https://docs.rs/zbus/4/zbus/proxy/struct.Builder.html#method.uncached_properties
[`proxy::Builder::cache_properites`]: https://docs.rs/zbus/4/zbus/proxy/struct.Builder.html#method.cache_properties
[`proxy`]: https://docs.rs/zbus/4/zbus/attr.proxy.html
Expand All @@ -160,3 +234,6 @@ enabled.
[`Optional<T>`]: https://docs.rs/zvariant/4/zvariant/struct.Optional.html
[`d-feet`]: https://wiki.gnome.org/Apps/DFeet
[specialization]: https://rust-lang.github.io/rfcs/1210-impl-specialization.html
[`Value`]: https://docs.rs/zvariant/4/zvariant/enum.Value.html
[`OwnedValue`]: https://docs.rs/zvariant/4/zvariant/struct.OwnedValue.html
[`serde_repr`]: https://crates.io/crates/serde_repr
28 changes: 21 additions & 7 deletions book/src/server.md → book/src/service.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Writing a server interface
# Writing a service interface

In this chapter, we are going to implement a server with a method "SayHello", to greet back the
<!-- toc -->

In this chapter, we are going to implement a service with a method "SayHello", to greet back the
calling client.

We will first discuss the need to associate a service name with the server. Then we are going to
We will first discuss the need to associate a service name with the service. Then we are going to
manually handle incoming messages using the low-level API. Finally, we will present the
`ObjectServer` higher-level API and some of its more advanced concepts.

Expand Down Expand Up @@ -37,12 +39,12 @@ We can check our service is running and is associated with the service name:

```bash
$ busctl --user list | grep zbus
org.zbus.MyGreeter 412452 server elmarco :1.396 user@1000.service - -
org.zbus.MyGreeter 412452 service elmarco :1.396 user@1000.service - -
```

### 🖐 Hang on

This example is not handling incoming messages yet. Any attempt to call the server will time out
This example is not handling incoming messages yet. Any attempt to call the service will time out
(including the shell completion!).

## Handling low-level messages
Expand Down Expand Up @@ -124,7 +126,7 @@ impl Greeter {
#[tokio::main]
async fn main() -> Result<()> {
let connection = Connection::session().await?;
// setup the server
// setup the object server
connection
.object_server()
.at("/org/zbus/MyGreeter", Greeter)
Expand Down Expand Up @@ -288,6 +290,16 @@ org.zbus.MyGreeter1 interface - - -
.GreetedEveryone signal - - -
```

### Trait-bounds for property values

If you use custom types for property values, you might get a compile error for missing
`TryFrom<zvariant::Value<'_>>` and/or `TryFrom<OwnedValue>` implementations. This is because
properties are always sent as Variants on the bus, so you need to implement these conversions for
your custom types.

Not to worry though, the `zvariant` crate provides a [`Value`] and [`OwnedValue`] derive macro to
implement these conversions for you.

### Method errors

There are two possibilities for the return value of interface methods. The first is for infallible
Expand Down Expand Up @@ -413,7 +425,7 @@ While it's extremely useful to be able to generate the client-side proxy code di
`interface` as it allows you to avoid duplicating code, there are some limitations to be aware of:

* The trait bounds of the `proxy` macro methods' arguments and return value, now also apply to the
`interface` methods. For example, when only generating the server-side code, the method return
`interface` methods. For example, when only generating the service-side code, the method return
values need to implement `serde::Serialize` but when generating the client-side proxy code, the
method return values need to implement `serde::DeserializeOwned` as well.
* Reference types in return values of `interface` methods won't work. As you may have noticed,
Expand All @@ -427,6 +439,8 @@ While it's extremely useful to be able to generate the client-side proxy code di

[D-Bus concepts]: concepts.html#bus-name--service-name
[didoc]: https://docs.rs/zbus/4/zbus/attr.interface.html
[`Value`]: https://docs.rs/zvariant/4/zvariant/derive.Value.html
[`OwnedValue`]: https://docs.rs/zvariant/4/zvariant/derive.OwnedValue.html
[`zbus::DBusError`]:https://docs.rs/zbus/4/zbus/trait.DBusError.html
[`zbus::fdo::Error`]: https://docs.rs/zbus/4/zbus/fdo/enum.Error.html
[`zbus::fdo::Error::UnknownProperty`]: https://docs.rs/zbus/4/zbus/fdo/enum.Error.html#variant.UnknownProperty
Expand Down
2 changes: 1 addition & 1 deletion zbus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mod doctests {
doc_comment::doctest!("../../book/src/connection.md");
doc_comment::doctest!("../../book/src/contributors.md");
doc_comment::doctest!("../../book/src/introduction.md");
doc_comment::doctest!("../../book/src/server.md");
doc_comment::doctest!("../../book/src/service.md");
doc_comment::doctest!("../../book/src/blocking.md");
doc_comment::doctest!("../../book/src/faq.md");
}
Expand Down

0 comments on commit 0ece0f0

Please sign in to comment.