[PATCH v3 00/19] rust: QObject and QAPI bindings

Paolo Bonzini posted 19 patches 3 days, 23 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260526175618.227743-1-pbonzini@redhat.com
Maintainers: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>, Markus Armbruster <armbru@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Michael Roth <michael.roth@amd.com>, Manos Pitsidianakis <manos.pitsidianakis@linaro.org>, "Alex Bennée" <alex.bennee@linaro.org>
docs/devel/rust.rst                           |   1 +
meson.build                                   |   4 +-
include/qobject/qobject.h                     |   5 +-
qapi/meson.build                              |   9 +
rust/Cargo.lock                               |   2 +
rust/Cargo.toml                               |   2 +
rust/meson.build                              |   4 +
rust/tests/meson.build                        |  21 +-
rust/tests/tests/integration.rs               |   2 +
rust/tests/tests/qapi.rs                      | 444 +++++++++++++
rust/util/Cargo.toml                          |   2 +
rust/util/meson.build                         |  19 +-
rust/util/src/lib.rs                          |   4 +
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                  | 385 ++++++++++++
rust/util/src/qobject/serialize.rs            |  57 ++
rust/util/src/qobject/serializer.rs           | 585 ++++++++++++++++++
scripts/archive-source.sh                     |   3 +
scripts/make-release                          |   2 +-
scripts/qapi/backend.py                       |  25 +
scripts/qapi/common.py                        |  94 ++-
scripts/qapi/rs.py                            |  50 ++
scripts/qapi/rs_types.py                      | 393 ++++++++++++
scripts/qapi/schema.py                        |  86 ++-
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 +
tests/qapi-schema/doc-good.json               |  16 +-
tests/qapi-schema/doc-good.out                |  12 +-
tests/qapi-schema/doc-good.txt                |   8 +-
tests/qapi-schema/enum-empty.err              |   2 +
tests/qapi-schema/enum-empty.json             |   2 +
tests/qapi-schema/enum-empty.out              |   0
tests/qapi-schema/enum-if-first-required.err  |   2 +
tests/qapi-schema/enum-if-first-required.json |   6 +
tests/qapi-schema/enum-if-first-required.out  |   0
tests/qapi-schema/meson.build                 |   2 +
tests/qapi-schema/qapi-schema-test.json       |   3 -
tests/qapi-schema/qapi-schema-test.out        |   1 -
tests/qapi-schema/union-empty.err             |   4 +-
50 files changed, 2951 insertions(+), 59 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
create mode 100644 tests/qapi-schema/enum-empty.err
create mode 100644 tests/qapi-schema/enum-empty.json
create mode 100644 tests/qapi-schema/enum-empty.out
create mode 100644 tests/qapi-schema/enum-if-first-required.err
create mode 100644 tests/qapi-schema/enum-if-first-required.json
create mode 100644 tests/qapi-schema/enum-if-first-required.out
[PATCH v3 00/19] rust: QObject and QAPI bindings
Posted by Paolo Bonzini 3 days, 23 hours ago
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.

The main change from v2 is the introduction of two patches to
restrict a bit the QAPI language and embed some things that Rust's
type system enforces.  I think both of them are sensible
restrictions in general:

- new patch "scripts/qapi: reject empty enums", because empty enums
  cannot have any plausible meaning.  Note that if all items are
  conditional the enum is still allowed;

- new patch "scripts/qapi: enum with conditional first item must
  be optional", to avoid giving different meanings to an all zero
  struct; and also happening to catch the "all items are conditional"
  case of the previous patch, ensuring that structs containing that
  enum can be created.

Everything else is mostly cosmetic.

Paolo

v2->v3:
- QObject bindgen already done by rust/bindings/util-sys
- meson build rules are simpler due to util-sys vs util split
- comment adjustments for qobject/mod.rs
- preserve error from CStr::to_str() and CString::new()
- add de::Error implementation for qobject::error::Error
- new patch "scripts/qapi: reject empty enums"
- new patch "scripts/qapi: enum with conditional first item must be optional"
- add comment to commit message on why camer_to_upper()'s callers use
  lstrip('_') for C
- new patch "allow passing multiple segments to mcgen" to improve
  code formatting (fewer empty lines)
- add comment to commit message on why Rust for now is a separate backend
- rewrite to_camel_case(), changing 'foo-0123-bar' to 'Foo0123Bar' instead
  of 'Foo_0123Bar'
- use blurb argument for QAPIGenRs constructor


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

Paolo Bonzini (13):
  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/qobject: add from/to JSON bindings for QObject
  scripts/qapi: reject empty enums
  scripts/qapi: enum with conditional first item must be optional
  scripts/qapi: add QAPISchemaType.is_predefined
  scripts/qapi: pull c_name and lstrip from camel_to_upper to caller
  scripts/qapi: allow passing multiple segments to mcgen
  scripts/qapi: add serde attributes

 docs/devel/rust.rst                           |   1 +
 meson.build                                   |   4 +-
 include/qobject/qobject.h                     |   5 +-
 qapi/meson.build                              |   9 +
 rust/Cargo.lock                               |   2 +
 rust/Cargo.toml                               |   2 +
 rust/meson.build                              |   4 +
 rust/tests/meson.build                        |  21 +-
 rust/tests/tests/integration.rs               |   2 +
 rust/tests/tests/qapi.rs                      | 444 +++++++++++++
 rust/util/Cargo.toml                          |   2 +
 rust/util/meson.build                         |  19 +-
 rust/util/src/lib.rs                          |   4 +
 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                  | 385 ++++++++++++
 rust/util/src/qobject/serialize.rs            |  57 ++
 rust/util/src/qobject/serializer.rs           | 585 ++++++++++++++++++
 scripts/archive-source.sh                     |   3 +
 scripts/make-release                          |   2 +-
 scripts/qapi/backend.py                       |  25 +
 scripts/qapi/common.py                        |  94 ++-
 scripts/qapi/rs.py                            |  50 ++
 scripts/qapi/rs_types.py                      | 393 ++++++++++++
 scripts/qapi/schema.py                        |  86 ++-
 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 +
 tests/qapi-schema/doc-good.json               |  16 +-
 tests/qapi-schema/doc-good.out                |  12 +-
 tests/qapi-schema/doc-good.txt                |   8 +-
 tests/qapi-schema/enum-empty.err              |   2 +
 tests/qapi-schema/enum-empty.json             |   2 +
 tests/qapi-schema/enum-empty.out              |   0
 tests/qapi-schema/enum-if-first-required.err  |   2 +
 tests/qapi-schema/enum-if-first-required.json |   6 +
 tests/qapi-schema/enum-if-first-required.out  |   0
 tests/qapi-schema/meson.build                 |   2 +
 tests/qapi-schema/qapi-schema-test.json       |   3 -
 tests/qapi-schema/qapi-schema-test.out        |   1 -
 tests/qapi-schema/union-empty.err             |   4 +-
 50 files changed, 2951 insertions(+), 59 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
 create mode 100644 tests/qapi-schema/enum-empty.err
 create mode 100644 tests/qapi-schema/enum-empty.json
 create mode 100644 tests/qapi-schema/enum-empty.out
 create mode 100644 tests/qapi-schema/enum-if-first-required.err
 create mode 100644 tests/qapi-schema/enum-if-first-required.json
 create mode 100644 tests/qapi-schema/enum-if-first-required.out

-- 
2.54.0