qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/19] rust: QObject and QAPI bindings
@ 2025-10-10 15:09 Paolo Bonzini
  2025-10-10 15:09 ` [PATCH 01/19] util: add ensure macro Paolo Bonzini
                   ` (18 more replies)
  0 siblings, 19 replies; 20+ messages in thread
From: Paolo Bonzini @ 2025-10-10 15:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, marcandre.lureau, qemu-rust

This adds two related parts of the Rust bindings:

- QAPI code generator that creates Rust structs from the JSON
  description.  The structs are *not* ABI compatible with the
  C ones, instead they use native Rust data types.

- QObject bindings and (de)serialization support, which can be used to
  convert QObjects to and from QAPI structs.

Unfortunately Rust code is not able to use visitors, other than by
creating an intermediate QObject.  This is because of the different
architecture of serde vs. QAPI visitors, and because visitor's
dual-purpose functions, where the same function is used by both input and
output visitors, rely heavily on the structs using the same representation
as the visitor arguments (for example NUL-terminated strings).

The serde format implementation was co-authored by me and Marc-André.
Marc-André did all the bug fixing and integration testing.

As an example of how this would be used, the marshaling functions for
QMP commands would look like this:

fn qmp_marshal_query_stats(args: *mut QDict,
    retp: *mut *mut QObject, errp: *mut *mut Error)
{
    let qobj = unsafe { QObject::cloned_from_raw(args.cast()) };

    let result = from_qobject::<StatsFilter>(qobj)
         .map_err(anyhow::Error::from)
         .and_then(qmp_query_stats)
         .and_then(|ret| to_qobject::<Vec<StatsResult>>(ret).map_err(anyhow::Error::from));

    match qmp_marshal_query_stats_rs(qobj) {
        Ok(ret) => unsafe { *retp = ret.into_raw(); },
        Err(e) => unsafe { crate::Error::from(e).propagate(errp) },
    }
}

As a small extra, patches 1 and 2 rework a bit the error implementation
so that it is possible to convert any Rust error into a QEMU one.  This
is because we noticed that we had to add several From<> implementations
to convert e.g. NulError or serde errors into util::Error.

The price is that it's a bit harder to convert *strings* into errors;
therefore, the first patch adds a macro wrapper for
"if !cond { return Err(...) }", where the dots build an error from a
formatted string.

Paolo

Marc-André Lureau (8):
  rust/qobject: add Display/Debug
  scripts/qapi: add QAPISchemaIfCond.rsgen()
  scripts/qapi: generate high-level Rust bindings
  scripts/qapi: add serde attributes
  scripts/qapi: strip trailing whitespaces
  scripts/rustc_args: add --no-strict-cfg
  rust/util: build QAPI types
  rust/tests: QAPI integration tests

Paolo Bonzini (11):
  util: add ensure macro
  rust/util: use anyhow's native chaining capabilities
  rust: do not add qemuutil to Rust crates
  rust/qobject: add basic bindings
  subprojects: add serde
  rust/qobject: add Serialize implementation
  rust/qobject: add Serializer (to_qobject) implementation
  rust/qobject: add Deserialize implementation
  rust/qobject: add Deserializer (from_qobject) implementation
  rust/util: replace Error::err_or_unit/err_or_else with
    Error::with_errp
  rust/qobject: add from/to JSON bindings for QObject

 docs/devel/rust.rst                           |   1 +
 meson.build                                   |   4 +-
 rust/util/wrapper.h                           |   8 +
 qapi/meson.build                              |   6 +
 rust/Cargo.lock                               |   2 +
 rust/Cargo.toml                               |   2 +
 rust/chardev/meson.build                      |   2 +-
 rust/hw/timer/hpet/src/device.rs              |  21 +-
 rust/hw/timer/hpet/src/fw_cfg.rs              |   7 +-
 rust/meson.build                              |   4 +
 rust/tests/meson.build                        |  25 +-
 rust/tests/tests/integration.rs               |   2 +
 rust/tests/tests/qapi.rs                      | 444 +++++++++++++
 rust/util/Cargo.toml                          |   2 +
 rust/util/meson.build                         |  31 +-
 rust/util/src/error.rs                        | 222 +++----
 rust/util/src/lib.rs                          |   2 +
 rust/util/src/qobject/deserialize.rs          | 134 ++++
 rust/util/src/qobject/deserializer.rs         | 371 +++++++++++
 rust/util/src/qobject/error.rs                |  58 ++
 rust/util/src/qobject/mod.rs                  | 369 +++++++++++
 rust/util/src/qobject/serialize.rs            |  59 ++
 rust/util/src/qobject/serializer.rs           | 585 ++++++++++++++++++
 scripts/archive-source.sh                     |   3 +
 scripts/make-release                          |   2 +-
 scripts/qapi/backend.py                       |  27 +-
 scripts/qapi/common.py                        |  16 +
 scripts/qapi/gen.py                           |   6 +-
 scripts/qapi/main.py                          |   4 +-
 scripts/qapi/rs.py                            | 181 ++++++
 scripts/qapi/rs_types.py                      | 387 ++++++++++++
 scripts/qapi/schema.py                        |   4 +
 scripts/rust/rustc_args.py                    |  16 +-
 subprojects/.gitignore                        |   3 +
 .../packagefiles/serde-1-rs/meson.build       |  36 ++
 .../packagefiles/serde-1.0.226-include.patch  |  16 +
 .../packagefiles/serde_core-1-rs/meson.build  |  25 +
 .../serde_core-1.0.226-include.patch          |  15 +
 .../serde_derive-1-rs/meson.build             |  35 ++
 .../serde_derive-1.0.226-include.patch        |  11 +
 subprojects/serde-1-rs.wrap                   |  11 +
 subprojects/serde_core-1-rs.wrap              |  11 +
 subprojects/serde_derive-1-rs.wrap            |  11 +
 43 files changed, 3042 insertions(+), 139 deletions(-)
 create mode 100644 rust/tests/tests/integration.rs
 create mode 100644 rust/tests/tests/qapi.rs
 create mode 100644 rust/util/src/qobject/deserialize.rs
 create mode 100644 rust/util/src/qobject/deserializer.rs
 create mode 100644 rust/util/src/qobject/error.rs
 create mode 100644 rust/util/src/qobject/mod.rs
 create mode 100644 rust/util/src/qobject/serialize.rs
 create mode 100644 rust/util/src/qobject/serializer.rs
 create mode 100644 scripts/qapi/rs.py
 create mode 100644 scripts/qapi/rs_types.py
 create mode 100644 subprojects/packagefiles/serde-1-rs/meson.build
 create mode 100644 subprojects/packagefiles/serde-1.0.226-include.patch
 create mode 100644 subprojects/packagefiles/serde_core-1-rs/meson.build
 create mode 100644 subprojects/packagefiles/serde_core-1.0.226-include.patch
 create mode 100644 subprojects/packagefiles/serde_derive-1-rs/meson.build
 create mode 100644 subprojects/packagefiles/serde_derive-1.0.226-include.patch
 create mode 100644 subprojects/serde-1-rs.wrap
 create mode 100644 subprojects/serde_core-1-rs.wrap
 create mode 100644 subprojects/serde_derive-1-rs.wrap

-- 
2.51.0



^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2025-10-10 15:18 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-10 15:09 [PATCH 00/19] rust: QObject and QAPI bindings Paolo Bonzini
2025-10-10 15:09 ` [PATCH 01/19] util: add ensure macro Paolo Bonzini
2025-10-10 15:09 ` [PATCH 02/19] rust/util: use anyhow's native chaining capabilities Paolo Bonzini
2025-10-10 15:09 ` [PATCH 03/19] rust: do not add qemuutil to Rust crates Paolo Bonzini
2025-10-10 15:09 ` [PATCH 04/19] rust/qobject: add basic bindings Paolo Bonzini
2025-10-10 15:09 ` [PATCH 05/19] subprojects: add serde Paolo Bonzini
2025-10-10 15:09 ` [PATCH 06/19] rust/qobject: add Serialize implementation Paolo Bonzini
2025-10-10 15:09 ` [PATCH 07/19] rust/qobject: add Serializer (to_qobject) implementation Paolo Bonzini
2025-10-10 15:09 ` [PATCH 08/19] rust/qobject: add Deserialize implementation Paolo Bonzini
2025-10-10 15:09 ` [PATCH 09/19] rust/qobject: add Deserializer (from_qobject) implementation Paolo Bonzini
2025-10-10 15:09 ` [PATCH 10/19] rust/util: replace Error::err_or_unit/err_or_else with Error::with_errp Paolo Bonzini
2025-10-10 15:09 ` [PATCH 11/19] rust/qobject: add from/to JSON bindings for QObject Paolo Bonzini
2025-10-10 15:09 ` [PATCH 12/19] rust/qobject: add Display/Debug Paolo Bonzini
2025-10-10 15:09 ` [PATCH 13/19] scripts/qapi: add QAPISchemaIfCond.rsgen() Paolo Bonzini
2025-10-10 15:09 ` [PATCH 14/19] scripts/qapi: generate high-level Rust bindings Paolo Bonzini
2025-10-10 15:10 ` [PATCH 15/19] scripts/qapi: add serde attributes Paolo Bonzini
2025-10-10 15:10 ` [PATCH 16/19] scripts/qapi: strip trailing whitespaces Paolo Bonzini
2025-10-10 15:10 ` [PATCH 17/19] scripts/rustc_args: add --no-strict-cfg Paolo Bonzini
2025-10-10 15:10 ` [PATCH 18/19] rust/util: build QAPI types Paolo Bonzini
2025-10-10 15:10 ` [PATCH 19/19] rust/tests: QAPI integration tests Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).