From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818352; cv=none; d=zohomail.com; s=zohoarc; b=ezzW6654fIC7Lk++TR8JZia3Plr0xRoyXA+VJ96mR8/dMMI4QWWv9ZLJ35KBSR3F8nXyxm+FMwG8zPkVQeDUe/Y10J8v4th2oKiQ2+aWhhC8mq+UeLrWr8om4/pZHn+WyBbSLuPpcx4cBilnl6e9cTrHzGMqNl2sS6TK5ouC9eM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818352; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=FAcLiKCSXLRb9arAXRZkzh+D3RnWx3VHk4itjUtPIUY=; b=PmNDDfVXKhd4od02+wdY5ORfU/NM54a0IG55QPN6E5q0yMoJSYvc8aG9moBDpXP4XYuGy1JkUvsT5H2Y56XdpL4/YxCOA+cjGGX0o3NMgQmez/NJ6gOYClLyqX3CmIqrfCxlpiT1VI6sY6bLzAROEyOWy0lgTvpm9HCiE5oGCZ0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818352801606.5813016482814; Tue, 26 May 2026 10:59:12 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw13-0001uZ-QE; Tue, 26 May 2026 13:56:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw12-0001t9-1O for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:32 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw0w-0007rJ-U4 for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:31 -0400 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-63-vbTw8GqVPRCfADLr16EP4Q-1; Tue, 26 May 2026 13:56:24 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-48fed2519daso50324625e9.0 for ; Tue, 26 May 2026 10:56:23 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490454c60b5sm376108515e9.1.2026.05.26.10.56.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818185; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FAcLiKCSXLRb9arAXRZkzh+D3RnWx3VHk4itjUtPIUY=; b=dg8u5Mq5dKC83d6NUc5UdmZ4uE6voZqR6d0IcnaQCoYIlOpCtRZrdUBuH3JpvLIU4VXkKG zXN4ruxk/xsOfoNx+ieGWzEqI/bEBLwXtJe7m4CAGskRmJmn2YOtSyDhBwYapDqkP/8ko6 27PaZcRF8ePlqLKmR2Q4jEn//PwXsEI= X-MC-Unique: vbTw8GqVPRCfADLr16EP4Q-1 X-Mimecast-MFC-AGG-ID: vbTw8GqVPRCfADLr16EP4Q_1779818183 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818183; x=1780422983; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FAcLiKCSXLRb9arAXRZkzh+D3RnWx3VHk4itjUtPIUY=; b=LKBwLtMUSbNS5OSeTb45B9TOmRQuUgq37dLEtq9LSrIn34tXA4CbyneUWhgP3E+CtV tv4p3aMd0cQNFCLtR4gO89na4cTPLtaBYv4Ni9knHQ+qFXvZtQdkpq1t2oD+Mo46AjvT Ji2uLOZdzZhOzzkAHmwpdKXkXI9Qmocid0DWjKbtv2Sgxfc/ZGZ2wYHgFlUdbFf+fB6q msrRxveZ2zVBJzSDAalwsTMYJfjBsd0a1L1M/l/12jRMWMOcoxRLL7n3OKsITP3tfdzs QG5kAbk88zs5Tbx0lbFXV1Ysr2B8wv665XrbTX3G1P8Q+5fYVKblhjP3uH3hpyxwWjqo MURw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818183; x=1780422983; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=FAcLiKCSXLRb9arAXRZkzh+D3RnWx3VHk4itjUtPIUY=; b=Qq7AmS0jlVAjQTkyKWTYhwhygoTH0/NqIGp7teUyXjH6WbGQ9R8ShgsqmBpYyw9lrL s+LKF504kNg7oT7w8K83GrNOMiGd6fSMlyY2LKAW0WSztXbV8DtBvWPGvbGa/XIu0PRh syt45PlgaJ+Ie6JIPI50DfucjefqpZBRrTyCCQqnySDOu+jr7vVnRaASb90eua6OSXOt d7qn/vq/Wu9ReiC/mEwZkuNIJbARc/9YMNtqvdMg+NAtNYMlw34tg190+Ih5a1XvOdrP DIaow8i3aPwsBz1y7pn7aAeVLUtz5WEHck+w6UaaYl6YA0K9FX66LH579twRBFB+djPd h5aQ== X-Gm-Message-State: AOJu0YwGItW6biN2s7zu9tH6Po6For27R7t6XgctAtI9RCGk/jLNbW1V b0bLG6q++lYS1GWzV4PFOhmpexg5SRfZFaNMAY6bXvszxWZn+BMH+1HAdVWkwjHV1jLo9MUPiGE eYE7HmVIWd7thiymqN9c7M2BEoum79KAbckMvdjNk9ub4M9PMcPbapy/m41gaESkTxTdYNqDDwN 3V8Tbt8WAStMAQVXPYUu9svpuPA74EgAHnm8lpVYAI X-Gm-Gg: Acq92OEer39IlfO/T6g/5OcK+ebEN4k8+gEL8oOY21J4+9mmTq6gp806NDRXrLb/TqN dzHjC5rWRXfO3YWuuB9qxZY33+ONlzR8UY8fOpCVViCxIUJEaXGRaS9Dp4Fc4uKLDe5dXV6NgQH uQrAwcpI3qdglyUFN434wTU25dxsPL7qcD75VrNlZiQFn6hSdUYoXXiGn84Xslxb3pGDvCxqsJI 6B2YhIqFW7d+B17q3pAI3yvag7W+mwsI+pW/QwyBbw6iJ8Gije91pXeEsqlJD+pi/iUIzxJwt7s +jrzWl0ABbsSKT2ag4veBmR2NSmrbS7tGfQ78AYMiUXig1UBGQ90V1L8uUFMvqJkNrshZrngpZp apiOfF/48AJxkA2fXrtxxAZOL1n6Eu1jxyRbi3QpBxWE6ehpKP680XG0sSjO50Y6hIVvv4lmodw 7pH04LTevpLAZsNGQJrGq/wezqH0A= X-Received: by 2002:a05:600c:4591:b0:490:6869:46c6 with SMTP id 5b1f17b1804b1-490686947a8mr134937455e9.31.1779818182510; Tue, 26 May 2026 10:56:22 -0700 (PDT) X-Received: by 2002:a05:600c:4591:b0:490:6869:46c6 with SMTP id 5b1f17b1804b1-490686947a8mr134936785e9.31.1779818181906; Tue, 26 May 2026 10:56:21 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com, Zhao Liu Subject: [PATCH v3 01/19] rust/qobject: add basic bindings Date: Tue, 26 May 2026 19:56:00 +0200 Message-ID: <20260526175618.227743-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818353981158500 This is only a basic API, intended to be used by the serde traits. Co-authored-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- include/qobject/qobject.h | 5 +- rust/util/src/lib.rs | 4 + rust/util/src/qobject/mod.rs | 333 +++++++++++++++++++++++++++++++++++ 3 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 rust/util/src/qobject/mod.rs diff --git a/include/qobject/qobject.h b/include/qobject/qobject.h index 02f4c6a6eb2..f5bbcf243f7 100644 --- a/include/qobject/qobject.h +++ b/include/qobject/qobject.h @@ -35,7 +35,10 @@ #include "qemu/atomic.h" #include "qapi/qapi-builtin-types.h" =20 -/* Not for use outside include/qobject/ */ +/* + * Not for use outside include/qobject/ (and Rust bindings, when they + * have to redo inline functions defined here). + */ struct QObjectBase_ { QType type; size_t refcnt; diff --git a/rust/util/src/lib.rs b/rust/util/src/lib.rs index 436c67e139e..4793c23f4b0 100644 --- a/rust/util/src/lib.rs +++ b/rust/util/src/lib.rs @@ -10,6 +10,10 @@ // for prelude-like modules #[rustfmt::skip] pub mod prelude; + +#[macro_use] +pub mod qobject; + pub mod timer; =20 pub use error::{Error, Result, ResultExt}; diff --git a/rust/util/src/qobject/mod.rs b/rust/util/src/qobject/mod.rs new file mode 100644 index 00000000000..210078ea23e --- /dev/null +++ b/rust/util/src/qobject/mod.rs @@ -0,0 +1,333 @@ +//! `QObject` bindings +//! +//! This module implements bindings for QEMU's `QObject` data structure. +//! The bindings integrate with `serde`, which take the role of visitors +//! in Rust code. + +#![deny(clippy::unwrap_used)] + +use std::{ + cell::UnsafeCell, + ffi::{c_char, CString}, + mem::ManuallyDrop, + ptr::{addr_of, addr_of_mut}, + sync::atomic::{AtomicUsize, Ordering}, +}; + +use common::assert_field_type; + +use crate::bindings; + +/// A wrapper for a C `QObject`. +/// +/// Because `QObject` is not thread-safe, the safety of these bindings +/// right now hinges on treating them as immutable. It is part of the +/// contract with the `QObject` constructors that the Rust struct is +/// only built after the contents are stable. +/// +/// Only a bare bones API is public; production and consumption of `QObjec= t` +/// generally goes through `serde`. +pub struct QObject(&'static UnsafeCell); + +// SAFETY: the QObject API are not thread-safe other than reference counti= ng; +// but the Rust struct is only created once the contents are stable, and +// therefore it obeys the aliased XOR mutable invariant. +unsafe impl Send for QObject {} +unsafe impl Sync for QObject {} + +// Since a QObject can be a floating-point value, and potentially a NaN, +// do not implement Eq +impl PartialEq for QObject { + fn eq(&self, other: &Self) -> bool { + unsafe { bindings::qobject_is_equal(self.0.get(), other.0.get()) } + } +} + +impl QObject { + /// Construct a [`QObject`] from a C `QObjectBase_` pointer. + /// The caller cedes its reference to the returned struct. + /// + /// # Safety + /// + /// The `QObjectBase`_ must not be changed from C code while + /// the Rust `QObject` lives + const unsafe fn from_base(p: *const bindings::QObjectBase_) -> Self { + QObject(unsafe { &*p.cast() }) + } + + /// Construct a [`QObject`] from a C `QObject` pointer. + /// The caller cedes its reference to the returned struct. + /// + /// # Safety + /// + /// The `QObject` must not be changed from C code while + /// the Rust `QObject` lives. The caller must own a reference + /// to the `QObject`; if not, [`QObject::cloned_from_raw`] should + /// be used instead. + pub const unsafe fn from_raw(p: *const bindings::QObject) -> Self { + QObject(unsafe { &*p.cast() }) + } + + /// Obtain a raw C pointer from a reference. `self` is consumed + /// without decreasing the reference count; therefore, the reference + /// is transferred to the `*mut bindings::QObject`. + pub fn into_raw(self) -> *mut bindings::QObject { + let src =3D ManuallyDrop::new(self); + src.0.get() + } + + /// Construct a [`QObject`] from a C `QObjectBase`_ pointer. + /// The caller *does not* cede its reference to the returned struct. + /// + /// # Safety + /// + /// The `QObjectBase`_ must not be changed from C code while + /// the Rust `QObject` lives + unsafe fn cloned_from_base(p: *const bindings::QObjectBase_) -> Self { + let orig =3D unsafe { ManuallyDrop::new(QObject::from_base(p)) }; + (*orig).clone() + } + + /// Construct a [`QObject`] from a C `QObject` pointer. + /// The caller *does not* cede its reference to the returned struct. + /// + /// # Safety + /// + /// The `QObject` must not be changed from C code while + /// the Rust `QObject` lives + pub unsafe fn cloned_from_raw(p: *const bindings::QObject) -> Self { + let orig =3D unsafe { ManuallyDrop::new(QObject::from_raw(p)) }; + (*orig).clone() + } + + fn refcnt(&self) -> &AtomicUsize { + assert_field_type!(bindings::QObjectBase_, refcnt, usize); + let qobj =3D self.0.get(); + unsafe { AtomicUsize::from_ptr(addr_of_mut!((*qobj).base.refcnt)) } + } +} + +/// Rust equivalent of the C `QOBJECT` macro; for internal use only, becau= se +/// all access should go through `From` (which already returns [`QObject`] +/// or serde. +macro_rules! qobject { + ($qobj:expr) =3D> {{ + let qobj: &bindings::QObjectBase_ =3D &$qobj.base; + // SAFETY: this `let` guarantees that either $qobj is a reference + // (not a raw pointer), or we're in an outer unsafe block + unsafe { QObject::from_base(qobj) } + }}; +} + +impl From<()> for QObject { + fn from(_null: ()) -> Self { + // Conversion of the C inline `qnull` function + unsafe { QObject::cloned_from_base(addr_of!(bindings::qnull_.base)= ) } + } +} + +impl From> for QObject +where + QObject: From, +{ + fn from(o: Option) -> Self { + o.map_or_else(|| ().into(), Into::into) + } +} + +impl From for QObject { + fn from(b: bool) -> Self { + let qobj =3D unsafe { &*bindings::qbool_from_bool(b) }; + qobject!(qobj) + } +} + +macro_rules! impl_from_return_qnum_int { + ($t:ty) =3D> { + impl From<$t> for QObject { + fn from(n: $t) -> Self { + let qobj =3D unsafe { &*bindings::qnum_from_int(n.into()) = }; + qobject!(qobj) + } + } + }; +} + +impl_from_return_qnum_int!(i8); +impl_from_return_qnum_int!(i16); +impl_from_return_qnum_int!(i32); +impl_from_return_qnum_int!(i64); + +macro_rules! impl_from_return_qnum_uint { + ($t:ty) =3D> { + impl From<$t> for QObject { + fn from(n: $t) -> Self { + let qobj =3D unsafe { &*bindings::qnum_from_uint(n.into())= }; + qobject!(qobj) + } + } + }; +} + +impl_from_return_qnum_uint!(u8); +impl_from_return_qnum_uint!(u16); +impl_from_return_qnum_uint!(u32); +impl_from_return_qnum_uint!(u64); + +macro_rules! impl_from_return_qnum_double { + ($t:ty) =3D> { + impl From<$t> for QObject { + fn from(n: $t) -> Self { + let qobj =3D unsafe { &*bindings::qnum_from_double(n.into(= )) }; + qobject!(qobj) + } + } + }; +} + +impl_from_return_qnum_double!(f32); +impl_from_return_qnum_double!(f64); + +impl From for QObject { + fn from(s: CString) -> Self { + let qobj =3D unsafe { &*bindings::qstring_from_str(s.as_ptr()) }; + qobject!(qobj) + } +} + +impl FromIterator for QObject +where + Self: From, +{ + fn from_iter>(it: I) -> Self { + let qlist =3D unsafe { &mut *bindings::qlist_new() }; + for elem in it { + let elem: QObject =3D elem.into(); + let elem =3D elem.into_raw(); + unsafe { + bindings::qlist_append_obj(qlist, elem); + } + } + qobject!(qlist) + } +} + +impl FromIterator<(CString, A)> for QObject +where + Self: From, +{ + fn from_iter>(it: I) -> Self { + let qdict =3D unsafe { &mut *bindings::qdict_new() }; + for (key, val) in it { + let val: QObject =3D val.into(); + let val =3D val.into_raw(); + unsafe { + bindings::qdict_put_obj(qdict, key.as_ptr().cast::= (), val); + } + } + qobject!(qdict) + } +} + +impl Clone for QObject { + fn clone(&self) -> Self { + self.refcnt().fetch_add(1, Ordering::Acquire); + QObject(self.0) + } +} + +impl Drop for QObject { + fn drop(&mut self) { + if self.refcnt().fetch_sub(1, Ordering::Release) =3D=3D 1 { + unsafe { + bindings::qobject_destroy(self.0.get()); + } + } + } +} + +#[allow(unused)] +macro_rules! match_qobject { + (@internal ($qobj:expr) =3D> + $(() =3D> $unit:expr,)? + $(bool($boolvar:tt) =3D> $bool:expr,)? + $(i64($i64var:tt) =3D> $i64:expr,)? + $(u64($u64var:tt) =3D> $u64:expr,)? + $(f64($f64var:tt) =3D> $f64:expr,)? + $(CStr($cstrvar:tt) =3D> $cstr:expr,)? + $(QList($qlistvar:tt) =3D> $qlist:expr,)? + $(QDict($qdictvar:tt) =3D> $qdict:expr,)? + $(_ =3D> $other:expr,)? + ) =3D> { + loop { + let qobj_ =3D $qobj.0.get(); + match unsafe { &* qobj_ }.base.type_ { + $($crate::bindings::QTYPE_QNULL =3D> break $unit,)? + $($crate::bindings::QTYPE_QBOOL =3D> break { + let qbool__: *mut $crate::bindings::QBool =3D qobj_.ca= st(); + let $boolvar =3D unsafe { (&*qbool__).value }; + $bool + },)? + $crate::bindings::QTYPE_QNUM =3D> { + let qnum__: *mut $crate::bindings::QNum =3D qobj_.cast= (); + let qnum__ =3D unsafe { &*qnum__ }; + match qnum__.kind { + $crate::bindings::QNUM_I64 | + $crate::bindings::QNUM_U64 | + $crate::bindings::QNUM_DOUBLE =3D> {} + _ =3D> { + panic!("unreachable"); + } + } + + match qnum__.kind { + $($crate::bindings::QNUM_I64 =3D> break { + let $i64var =3D unsafe { qnum__.u.i64_ }; + $i64 + },)? + $($crate::bindings::QNUM_U64 =3D> break { + let $u64var =3D unsafe { qnum__.u.u64_ }; + $u64 + },)? + $($crate::bindings::QNUM_DOUBLE =3D> break { + let $f64var =3D unsafe { qnum__.u.dbl }; + $f64 + },)? + _ =3D> {} // evaluate $other + } + }, + $($crate::bindings::QTYPE_QSTRING =3D> break { + let qstring__: *mut $crate::bindings::QString =3D qobj= _.cast(); + let $cstrvar =3D unsafe { ::core::ffi::CStr::from_ptr(= (&*qstring__).string) }; + $cstr + },)? + $($crate::bindings::QTYPE_QLIST =3D> break { + let qlist__: *mut $crate::bindings::QList =3D qobj_.ca= st(); + let $qlistvar =3D unsafe { &*qlist__ }; + $qlist + },)? + $($crate::bindings::QTYPE_QDICT =3D> break { + let qdict__: *mut $crate::bindings::QDict =3D qobj_.ca= st(); + let $qdictvar =3D unsafe { &*qdict__ }; + $qdict + },)? + _ =3D> () + }; + $(break $other;)? + #[allow(unreachable_code)] + { + panic!("unreachable"); + } + } + }; + + // first cleanup the syntax a bit, checking that there's at least + // one pattern and always adding a trailing comma + (($qobj:expr) =3D> + $($type:tt$(($val:tt))? =3D> $code:expr ),+ $(,)?) =3D> { + match_qobject!(@internal ($qobj) =3D> + $($type $(($val))? =3D> $code,)+) + }; +} +#[allow(unused_imports)] +use match_qobject; --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818437; cv=none; d=zohomail.com; s=zohoarc; b=Pa27/9R3SbPLKhYQ8XwaTb3w1uadKUTHouiXFfJWk43VpLbb6klWtycNeLeiJQxzaPLCAg3vyA/Yr+uNK9f5MxPk3482favswxunorpnTqM3fPn8BwnJxhMD/Bhk044mxd75MF13LA5d88UuvgjPxmfdZwYOripRhUfjz0iUFbQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818437; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=R5CLYiZa1ILjNlGC8UT56sIr6oHjsYHc7jOTEIWJqNI=; b=caUMs16BgtprteI4cJMMj36NDlnrjvMv2hgIbeX5ruHFvWUpyVQY8VFIT8CyV5CYFhWiUBZlVeHMx6WViVs8kPdMts2Ijn139ctHyiNsYPxH35ZnvRDYNJxPr4ZmwnzQqDtzSeDN+h9oGtcvnix0biRiYgj1fX6kDBdFmchymEE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818437182683.2847232397185; Tue, 26 May 2026 11:00:37 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw15-0001vb-DU; Tue, 26 May 2026 13:56:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw11-0001t7-VA for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:32 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw0y-0007rz-1t for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:31 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-355--so7Bn4AOV-M3xGPMNy41A-1; Tue, 26 May 2026 13:56:25 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-490479c2911so48545315e9.2 for ; Tue, 26 May 2026 10:56:25 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49045284855sm347569925e9.0.2026.05.26.10.56.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818187; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=R5CLYiZa1ILjNlGC8UT56sIr6oHjsYHc7jOTEIWJqNI=; b=amzrSDw+bR4dsjhglpYaJsbTJZ09l9K4Yrt6IanjO0cHgUYABLNnUBJPCeB7WSb9+9vpI0 B0C8fp1Pdkl4ROlWRG8be/ntgOAZdFXjoqydDApQaYIoeE+v+N5te0wyU9k8GNyy7FfPBa dGVQn/Er0fd/HCY7zE/ALek8BMVpWfA= X-MC-Unique: -so7Bn4AOV-M3xGPMNy41A-1 X-Mimecast-MFC-AGG-ID: -so7Bn4AOV-M3xGPMNy41A_1779818185 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818185; x=1780422985; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=R5CLYiZa1ILjNlGC8UT56sIr6oHjsYHc7jOTEIWJqNI=; b=jYJoQKidT93Dv9wokMNgA/sw7glq/kf3rqupmaPXiLBBWzAzasK98mJTdW10A7CaAX G65RojcNbw+mAk4KivSzFATx7T1FgUZaDe/ZsPOTx3WUWbTc5ZkEFcCYrxtPESsve+rZ B58gzum0zOpZz1xAq/aubO5FgOpBGd/TZQeE/sX3Z3RUiqs7UOUnBuB2w1eRJ4rzio9n X4XPhZxjUB/wGwa2pYuNGshoWFxLkg1wKQUM5t3t5Sx5Doe77mfA8Dw5ZUDn/I6suWcX BtgOwWmZmkoG49KF+m8yif13UgOQvbZltf5Yt++La+f5Fs2tW/vlWOnZo/4Ujo3Q0zpD 0qLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818185; x=1780422985; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=R5CLYiZa1ILjNlGC8UT56sIr6oHjsYHc7jOTEIWJqNI=; b=JfEoomixRjZpyDMqrkujIFa3PMSqgptCRgoSEosJdYmRyfkAdE89RDrNL6BWXv52qE GtcpanmyznkApzmjariy4es90SAdXMkVrM3X4MJh4d2r9/sGAHFzWz0Dk/tnfOvbZmqU 1NDnv4b3pYqezvzb9kr1W0uYuXQny1dzTBFAXihQUx1g4H7CbY0BOfAgNEbzXQnHIpmg Y++IhosmYMedCVf57kfiPvZWfPi9pYCtVsMIUXG6X4aulqd+uzgzVSK7zc10RiZ9FWKZ ZaNmaGAusaHYg2NuLwAxfrnjDG9BVSD2c86Zw5utD9T8umgX9uBmvqqmnn1yM9/IsskM Y6+g== X-Gm-Message-State: AOJu0YxRHa+Z+A+p73daajpMAi/q2ZtkJqYoDo8KJmlt6nDzTAs5AKo9 /Xy31v8S618Dr4VKyxKQ6sGJaSM2GGnxToQC1Bpn5DMMUml5horOYcSDSuXiwRDjmbGHW9BXB3H 01mtjvL9nS7xxTH5c276JPc9LIUcGA4H6iAW3+aAwOSTurPD0A8/j0noK5UVbrBngHT4JLE9o/o JcdM8IyK/HaDVCz5y8mpEzNTop7BtAYycJVdhrIL5y X-Gm-Gg: Acq92OFvJftSh4Sqf9AA9pRuOnD5DcizP+wk3MBuFeME1vdRQVuv7NYmSbCSGgNczMD U3VGRI0bQ+HK/c4b/dwPnUbl6ctK5Qdh6Qj00DF0FQOkJhSv0iGh7xhPAuTTu0CGCW+9iBF5YQX y9yBqq8ZXSawWTgU2gFFdkHuV9EHTWgtqnXuDRTiHBKlHnDpBajsTJvCja0BurCQ5hb3asoiENi 1/E0tFlc/HG9x/BtB7E3ZTlWjDoI+KrWsBHgdPaYja7sqNUg2cg6+Y/ntojMK4ef7DoF0U+I8Io z9laBBOv94P1wVPHAxOa7wEHOmHxPcQRW3cbOxgD5vwlz+EDolGmR5588spUWwbRXre9o3V61BZ 2RU9yv0x3MuVlDCmr9645qJ2jpiHnXwJ2dUiYRDolgRUgYULx1X8I8CWCKbX8JmM7mWPAVFFrNV szvE+RECuF4dQYJUBRai6IwfViHPM= X-Received: by 2002:a05:600c:3b9f:b0:48d:35e:82cb with SMTP id 5b1f17b1804b1-490428e93d6mr356021625e9.28.1779818184546; Tue, 26 May 2026 10:56:24 -0700 (PDT) X-Received: by 2002:a05:600c:3b9f:b0:48d:35e:82cb with SMTP id 5b1f17b1804b1-490428e93d6mr356021165e9.28.1779818184096; Tue, 26 May 2026 10:56:24 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com, Zhao Liu Subject: [PATCH v3 02/19] subprojects: add serde Date: Tue, 26 May 2026 19:56:01 +0200 Message-ID: <20260526175618.227743-3-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818438666158500 Content-Type: text/plain; charset="utf-8" Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/Cargo.toml | 2 ++ rust/meson.build | 4 +++ scripts/archive-source.sh | 3 ++ scripts/make-release | 2 +- 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 ++++++ 14 files changed, 184 insertions(+), 1 deletion(-) 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.pat= ch create mode 100644 subprojects/packagefiles/serde_derive-1-rs/meson.build create mode 100644 subprojects/packagefiles/serde_derive-1.0.226-include.p= atch 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 diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 0d24eb84e1c..fe491f3aba6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -20,6 +20,8 @@ anyhow =3D "~1.0" foreign =3D "~0.3.1" libc =3D "0.2.162" glib-sys =3D { version =3D "0.21.2", features =3D ["v2_66"] } +serde =3D "1.0.226" +serde_derive =3D "1.0.226" =20 [workspace.lints.rust] unexpected_cfgs =3D { level =3D "deny", check-cfg =3D ['cfg(MESON)'] } diff --git a/rust/meson.build b/rust/meson.build index b6711fe77dd..96e93f56e22 100644 --- a/rust/meson.build +++ b/rust/meson.build @@ -11,6 +11,8 @@ subproject('foreign-0.3-rs', required: true) subproject('glib-sys-0.21-rs', required: true) subproject('libc-0.2-rs', required: true) subproject('probe-0.5-rs', required: true) +subproject('serde-1-rs', required: true) +subproject('serde_derive-1-rs', required: true) =20 anyhow_rs =3D dependency('anyhow-1-rs') bilge_rs =3D dependency('bilge-0.2-rs') @@ -19,6 +21,8 @@ foreign_rs =3D dependency('foreign-0.3-rs') glib_sys_rs =3D dependency('glib-sys-0.21-rs') libc_rs =3D dependency('libc-0.2-rs') probe_rs =3D dependency('probe-0.5-rs') +serde_rs =3D dependency('serde-1-rs') +serde_derive_rs =3D dependency('serde_derive-1-rs', native: true) =20 subproject('proc-macro2-1-rs', required: true) subproject('quote-1-rs', required: true) diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh index a37acab524e..ae768cf99f6 100755 --- a/scripts/archive-source.sh +++ b/scripts/archive-source.sh @@ -46,6 +46,9 @@ subprojects=3D( proc-macro-error-attr-1-rs proc-macro2-1-rs quote-1-rs + serde-1-rs + serde_core-1-rs + serde_derive-1-rs syn-2-rs unicode-ident-1-rs ) diff --git a/scripts/make-release b/scripts/make-release index 5f54b0e7939..23fef08bcf3 100755 --- a/scripts/make-release +++ b/scripts/make-release @@ -44,7 +44,7 @@ SUBPROJECTS=3D"libvfio-user keycodemapdb berkeley-softflo= at-3 bilge-impl-0.2-rs either-1-rs foreign-0.3-rs itertools-0.11-rs libc-0.2-rs probe-0.5-rs proc-macro2-1-rs proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs - syn-2-rs unicode-ident-1-rs" + serde-1-rs serde_core-1-rs serde_derive-1-rs syn-2-rs unicode-ident-1-rs" =20 src=3D"$1" version=3D"$2" diff --git a/subprojects/.gitignore b/subprojects/.gitignore index 011ce4dc3b7..2cdb0a6a910 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -21,6 +21,9 @@ /proc-macro-error-attr-* /proc-macro* /quote-* +/serde-* +/serde_core-* +/serde_derive-* /syn-* /unicode-ident-* =20 diff --git a/subprojects/packagefiles/serde-1-rs/meson.build b/subprojects/= packagefiles/serde-1-rs/meson.build new file mode 100644 index 00000000000..775e0120f24 --- /dev/null +++ b/subprojects/packagefiles/serde-1-rs/meson.build @@ -0,0 +1,36 @@ +project('serde-1-rs', 'rust', + meson_version: '>=3D1.5.0', + version: '1.0.226', + license: 'MIT OR Apache-2.0', + default_options: []) + +subproject('serde_core-1-rs', required: true) +subproject('serde_derive-1-rs', required: true) + +serde_core_dep =3D dependency('serde_core-1-rs') +serde_derive_dep =3D dependency('serde_derive-1-rs') + +_serde_rs =3D static_library( + 'serde', + files('src/lib.rs'), + gnu_symbol_visibility: 'hidden', + override_options: ['rust_std=3D2021', 'build.rust_std=3D2021'], + rust_abi: 'rust', + rust_args: [ + '--cap-lints', 'allow', + '--cfg', 'feature=3D"alloc"', + '--cfg', 'feature=3D"std"', + '--cfg', 'feature=3D"derive"', + ], + dependencies: [ + serde_core_dep, + serde_derive_dep, + ] +) + +serde_dep =3D declare_dependency( + link_with: _serde_rs, + dependencies: serde_derive_dep, +) + +meson.override_dependency('serde-1-rs', serde_dep) diff --git a/subprojects/packagefiles/serde-1.0.226-include.patch b/subproj= ects/packagefiles/serde-1.0.226-include.patch new file mode 100644 index 00000000000..92878136878 --- /dev/null +++ b/subprojects/packagefiles/serde-1.0.226-include.patch @@ -0,0 +1,16 @@ +--- a/src/lib.rs 2025-09-23 13:41:09.327582205 +0200 ++++ b/src/lib.rs 2025-09-23 13:41:23.043271856 +0200 +@@ -241,7 +241,12 @@ + #[doc(hidden)] + mod private; +=20 +-include!(concat!(env!("OUT_DIR"), "/private.rs")); ++#[doc(hidden)] ++pub mod __private_MESON { ++ #[doc(hidden)] ++ pub use crate::private::*; ++} ++use serde_core::__private_MESON as serde_core_private; +=20 + // Re-export #[derive(Serialize, Deserialize)]. + // diff --git a/subprojects/packagefiles/serde_core-1-rs/meson.build b/subproj= ects/packagefiles/serde_core-1-rs/meson.build new file mode 100644 index 00000000000..79c36f6b70e --- /dev/null +++ b/subprojects/packagefiles/serde_core-1-rs/meson.build @@ -0,0 +1,25 @@ +project('serde_core-1-rs', 'rust', + meson_version: '>=3D1.5.0', + version: '1.0.226', + license: 'MIT OR Apache-2.0', + default_options: []) + +_serde_core_rs =3D static_library( + 'serde_core', + files('src/lib.rs'), + gnu_symbol_visibility: 'hidden', + override_options: ['rust_std=3D2021', 'build.rust_std=3D2021'], + rust_abi: 'rust', + rust_args: [ + '--cap-lints', 'allow', + '--cfg', 'feature=3D"alloc"', + '--cfg', 'feature=3D"result"', + '--cfg', 'feature=3D"std"', + ], +) + +serde_core_dep =3D declare_dependency( + link_with: _serde_core_rs, +) + +meson.override_dependency('serde_core-1-rs', serde_core_dep) diff --git a/subprojects/packagefiles/serde_core-1.0.226-include.patch b/su= bprojects/packagefiles/serde_core-1.0.226-include.patch new file mode 100644 index 00000000000..d1321dfe272 --- /dev/null +++ b/subprojects/packagefiles/serde_core-1.0.226-include.patch @@ -0,0 +1,15 @@ +--- a/src/lib.rs 2025-09-23 13:32:40.872421170 +0200 ++++ b/src/lib.rs 2025-09-23 13:32:52.181098856 +0200 +@@ -263,7 +263,11 @@ + pub use core::result::Result; + } +=20 +-include!(concat!(env!("OUT_DIR"), "/private.rs")); ++#[doc(hidden)] ++pub mod __private_MESON { ++ #[doc(hidden)] ++ pub use crate::private::*; ++} +=20 + #[cfg(all(not(feature =3D "std"), no_core_error))] + mod std_error; diff --git a/subprojects/packagefiles/serde_derive-1-rs/meson.build b/subpr= ojects/packagefiles/serde_derive-1-rs/meson.build new file mode 100644 index 00000000000..6c1001a844a --- /dev/null +++ b/subprojects/packagefiles/serde_derive-1-rs/meson.build @@ -0,0 +1,35 @@ +project('serde_derive-1-rs', 'rust', + meson_version: '>=3D1.5.0', + version: '1.0.226', + license: 'MIT OR Apache-2.0', + default_options: []) + +subproject('quote-1-rs', required: true) +subproject('syn-2-rs', required: true) +subproject('proc-macro2-1-rs', required: true) + +quote_dep =3D dependency('quote-1-rs', native: true) +syn_dep =3D dependency('syn-2-rs', native: true) +proc_macro2_dep =3D dependency('proc-macro2-1-rs', native: true) + +rust =3D import('rust') + +_serde_derive_rs =3D rust.proc_macro( + 'serde_derive', + files('src/lib.rs'), + override_options: ['rust_std=3D2021', 'build.rust_std=3D2021'], + rust_args: [ + '--cap-lints', 'allow', + ], + dependencies: [ + quote_dep, + syn_dep, + proc_macro2_dep, + ], +) + +serde_derive_dep =3D declare_dependency( + link_with: _serde_derive_rs, +) + +meson.override_dependency('serde_derive-1-rs', serde_derive_dep) diff --git a/subprojects/packagefiles/serde_derive-1.0.226-include.patch b/= subprojects/packagefiles/serde_derive-1.0.226-include.patch new file mode 100644 index 00000000000..81d65564d29 --- /dev/null +++ b/subprojects/packagefiles/serde_derive-1.0.226-include.patch @@ -0,0 +1,11 @@ +--- a/src/lib.rs 2025-09-23 13:51:51.540191923 +0200 ++++ b/src/lib.rs 2025-09-23 13:52:07.690060195 +0200 +@@ -98,7 +98,7 @@ + impl private { + fn ident(&self) -> Ident { + Ident::new( +- concat!("__private", env!("CARGO_PKG_VERSION_PATCH")), ++ "__private_MESON", + Span::call_site(), + ) + } diff --git a/subprojects/serde-1-rs.wrap b/subprojects/serde-1-rs.wrap new file mode 100644 index 00000000000..56746dd0f43 --- /dev/null +++ b/subprojects/serde-1-rs.wrap @@ -0,0 +1,11 @@ +[wrap-file] +directory =3D serde-1.0.226 +source_url =3D https://crates.io/api/v1/crates/serde/1.0.226/download +source_filename =3D serde-1.0.226.0.tar.gz +source_hash =3D 0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b5= 1295fd +#method =3D cargo +diff_files =3D serde-1.0.226-include.patch +patch_directory =3D serde-1-rs + +# bump this version number on every change to meson.build or the patches: +# v1 diff --git a/subprojects/serde_core-1-rs.wrap b/subprojects/serde_core-1-rs= .wrap new file mode 100644 index 00000000000..3692e754935 --- /dev/null +++ b/subprojects/serde_core-1-rs.wrap @@ -0,0 +1,11 @@ +[wrap-file] +directory =3D serde_core-1.0.226 +source_url =3D https://crates.io/api/v1/crates/serde_core/1.0.226/download +source_filename =3D serde_core-1.0.226.0.tar.gz +source_hash =3D ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99= e966a4 +#method =3D cargo +diff_files =3D serde_core-1.0.226-include.patch +patch_directory =3D serde_core-1-rs + +# bump this version number on every change to meson.build or the patches: +# v1 diff --git a/subprojects/serde_derive-1-rs.wrap b/subprojects/serde_derive-= 1-rs.wrap new file mode 100644 index 00000000000..00c92dc79cf --- /dev/null +++ b/subprojects/serde_derive-1-rs.wrap @@ -0,0 +1,11 @@ +[wrap-file] +directory =3D serde_derive-1.0.226 +source_url =3D https://crates.io/api/v1/crates/serde_derive/1.0.226/downlo= ad +source_filename =3D serde_derive-1.0.226.0.tar.gz +source_hash =3D 8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b56917169= 9cdb33 +#method =3D cargo +diff_files =3D serde_derive-1.0.226-include.patch +patch_directory =3D serde_derive-1-rs + +# bump this version number on every change to meson.build or the patches: +# v1 --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818401; cv=none; d=zohomail.com; s=zohoarc; b=b1KQpJMc16bgoxx0UB98bDtmQvOrBlEzxed3ExQ4JilRacHcWYuN6oCKEqQuXHB70jTRpPNBnUwSh1bttStsRwMgwpwuU5q8MC8SdMrwBydR4oIXn6Da/14TNhspKxkOV9uSReZBsIAsezvybWIAj2nMAygGovAM6JfP0uGucEQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818401; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=R5gaXZibmaGnGSJRfn9tMHw3pmY7HTP0M2qgx9cB7eU=; b=er4TC+nw4khpGGPJcunjJZEgVmEzgRGJgR9vPMryTWvqZlYFeP4vvCJir7ppkpZpLOC8MQV0XNvIwt/uC7x8djXkbW+5gLRmfYo6ZfvkOrIIDCwm9og6RjhK2S6i/Sdzm0LDTFO7+EUh+z40ZFsLBn0Ke/pLJ3EWWhshz/bA9wc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818401253323.4165749736288; Tue, 26 May 2026 11:00:01 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw15-0001vy-QM; Tue, 26 May 2026 13:56:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw14-0001v2-Hx for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:34 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw12-0007tC-FZ for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:34 -0400 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-602-GGl1wmx4M5mIxTHJWY2fgw-1; Tue, 26 May 2026 13:56:30 -0400 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-44d79da8cf7so8146666f8f.2 for ; Tue, 26 May 2026 10:56:30 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6d493dfsm38428882f8f.23.2026.05.26.10.56.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818191; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=R5gaXZibmaGnGSJRfn9tMHw3pmY7HTP0M2qgx9cB7eU=; b=BS+JKKoRu2FkvMs25IRSqdzjb9Y+VWvMZ4gEVTe7lH7FYPv1Q71Ttx5D+mlRwyFzeL6h6h yLEjWWAKmIvQx4UAazjoNJ0FVSn/ZJh6ZgCNn3iFp2boWCZOpXCnOEqlNv/iWmF5lczi5o A7kN8pZTK1yNmNi5dPumm56isylmbIM= X-MC-Unique: GGl1wmx4M5mIxTHJWY2fgw-1 X-Mimecast-MFC-AGG-ID: GGl1wmx4M5mIxTHJWY2fgw_1779818189 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818189; x=1780422989; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=R5gaXZibmaGnGSJRfn9tMHw3pmY7HTP0M2qgx9cB7eU=; b=VD8AM1ic86cskyZGngBqwcfuZPc3ahghxD/hVuPL+UyBiKug7szESCyjs9+kNNy3Mq 3+jDIPtt36v48w6O7vTeeSkM+fL6ERrvfrg3pyL88KN7gvx84cWbJqjjZgNRpfmnAKiY MVS6HGnrD3V7pJ1EB/93HLoregnmoRvHfAIZ+Og5WbVjyLrD0XG77YN8D3J3fujeU3Ap lSREFyhIBbYie+9TphVa/+jUb9XuMp4QJLBBaujYb0Uq+nuj7eYo74tvjWLAaJWeFxps NWieUpiNFPDJBizacaqf51LqxmqD67tUQY/q6gXCgxPFlLWHDCHIBqF13hQaLPO6wBUM pNhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818189; x=1780422989; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=R5gaXZibmaGnGSJRfn9tMHw3pmY7HTP0M2qgx9cB7eU=; b=nOsrx6jvyJtxQEgvgtIwIGPz31WiFeyhYOJAvt3OJ73DynsGQGz7BPOibG2euIwdxa zcDF8Xm8iYwZ5wcUHljsP+J7fbv+H60QQKIIx/r7r2mO870/fwklpX6emP0xQJQjHKU3 oVAlkVYf+tBakwA6+ZGZbAl3FOmmTsAQQPxJCmalbfrIJoVSSyqAlYqhkpsQaCUjb4S2 GOomUMnmIZ5R+DaZiVKkPOl+DBKfjo6WIQA3J+VYW2K4Aq8UTfwwwqobHP+PFrsoDFx0 7o/VKgvB1VkZFOmFBKoyvxwn2Q3ubWg7o3ag3fWi/ncI+spHAEpqtMmJ6XnunKvNz0YS nbrA== X-Gm-Message-State: AOJu0YzCg9snVSyK2SjuXH/vw2VP86UFV0QqZKRJFZzwHKL3XMaau9yQ I9ZGOw36/27AFMtAsimAG1zYTe18lcnIX406i0o4YeTx3bSPzzbvuUxk08Xt5RbI/YoEeulJiBy qBgSBhTNjZ4j6Fm6UMAQh0OyNwWT04Hl2/JcMeFBEMzJ4FpkpuUpTOq4Co8a1ZOKUmgLj4Ms5Zu jpcokd2OWcB2gVkdLthFqASla/JnRG+JyAaBI443My X-Gm-Gg: Acq92OGeVLrNjM8tY26p698bSQJkUPSGHy7d/yD3vILK9NTLk4VYBjT+VzlN5rKqpvp MlfAFZy5huGHF+tNc0AkAqki31XP/gC56Lf9gS9GuQ/0TLstXQKCRHS5ySXIilTmExkEDfS7a2F xZ68FPexUGdmfVVHB6JeG/mcq+tBn2WrbkF6LzrKzgq8K+6bPkcWbbuiI6HCWrhSt49+quM1oCx du+bsKPDCUqIMf8w50XBbkvyU/c8KsHOs4OIX6cD24Zyh+78+OkygWByvI+zK7uOJObD/ZOfpHT ICX2BB9ukBJ5aXmGT1NdPxmbYh+U5UWhS9nWIHiy7vZcpILazCPfruSu1ZfJSiFbYlClg1KfaLo ZDlJzuTYTxd7MA27fdzABxPtX5ssykF2i/rr81y2WDbRV50AiBaLVCdZz9aLauFFNeTFOLd2Quf +sgUwq4BqxcNvirUuYjnFiq/7DZA4= X-Received: by 2002:a05:6000:1884:b0:45e:da62:7a03 with SMTP id ffacd0b85a97d-45eda627a5fmr2701545f8f.15.1779818189035; Tue, 26 May 2026 10:56:29 -0700 (PDT) X-Received: by 2002:a05:6000:1884:b0:45e:da62:7a03 with SMTP id ffacd0b85a97d-45eda627a5fmr2701493f8f.15.1779818188523; Tue, 26 May 2026 10:56:28 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com, Zhao Liu Subject: [PATCH v3 03/19] rust/qobject: add Serialize implementation Date: Tue, 26 May 2026 19:56:02 +0200 Message-ID: <20260526175618.227743-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818402232158500 This allows QObject to be converted to other formats, for example JSON via serde_json. This is not too useful, since QObjects are consumed by C code or deserialized into structs, but it can be used for testing and it is part of the full implementation of a serde format. Co-authored-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/Cargo.lock | 1 + rust/util/Cargo.toml | 1 + rust/util/meson.build | 2 +- rust/util/src/qobject/mod.rs | 4 +-- rust/util/src/qobject/serialize.rs | 57 ++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 rust/util/src/qobject/serialize.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index cbb3ca15f77..b9e8636b8bc 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -513,6 +513,7 @@ dependencies =3D [ "foreign", "glib-sys", "libc", + "serde", "util-sys", ] =20 diff --git a/rust/util/Cargo.toml b/rust/util/Cargo.toml index 2ad5940daca..0a0400278f3 100644 --- a/rust/util/Cargo.toml +++ b/rust/util/Cargo.toml @@ -17,6 +17,7 @@ anyhow =3D { workspace =3D true } foreign =3D { workspace =3D true } glib-sys =3D { workspace =3D true } libc =3D { workspace =3D true } +serde =3D { workspace =3D true } common =3D { path =3D "../common" } util-sys =3D { path =3D "../bindings/util-sys" } =20 diff --git a/rust/util/meson.build b/rust/util/meson.build index 6d175ae0b0f..a8d9978e1a9 100644 --- a/rust/util/meson.build +++ b/rust/util/meson.build @@ -1,7 +1,7 @@ _util_rs =3D static_library( 'util', 'src/lib.rs', - dependencies: [anyhow_rs, libc_rs, foreign_rs, glib_sys_rs, common_rs, u= til_sys_rs], + dependencies: [anyhow_rs, libc_rs, foreign_rs, glib_sys_rs, common_rs, s= erde_rs, util_sys_rs], ) =20 util_rs =3D declare_dependency(link_with: [_util_rs], dependencies: [qemuu= til, qom]) diff --git a/rust/util/src/qobject/mod.rs b/rust/util/src/qobject/mod.rs index 210078ea23e..c42b75f3199 100644 --- a/rust/util/src/qobject/mod.rs +++ b/rust/util/src/qobject/mod.rs @@ -6,6 +6,8 @@ =20 #![deny(clippy::unwrap_used)] =20 +mod serialize; + use std::{ cell::UnsafeCell, ffi::{c_char, CString}, @@ -246,7 +248,6 @@ fn drop(&mut self) { } } =20 -#[allow(unused)] macro_rules! match_qobject { (@internal ($qobj:expr) =3D> $(() =3D> $unit:expr,)? @@ -329,5 +330,4 @@ macro_rules! match_qobject { $($type $(($val))? =3D> $code,)+) }; } -#[allow(unused_imports)] use match_qobject; diff --git a/rust/util/src/qobject/serialize.rs b/rust/util/src/qobject/ser= ialize.rs new file mode 100644 index 00000000000..97250602cc3 --- /dev/null +++ b/rust/util/src/qobject/serialize.rs @@ -0,0 +1,57 @@ +//! `QObject` serialization +//! +//! This module implements the [`Serialize`] trait for `QObject`, +//! allowing it to be converted to other formats, for example +//! JSON. + +use std::{ffi::CStr, mem::ManuallyDrop, ptr::addr_of}; + +use serde::ser::{self, Serialize, SerializeMap, SerializeSeq}; + +use super::{match_qobject, QObject}; +use crate::bindings; + +impl Serialize for QObject { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: ::serde::Serializer, + { + match_qobject! { (self) =3D> + () =3D> serializer.serialize_unit(), + bool(b) =3D> serializer.serialize_bool(b), + i64(i) =3D> serializer.serialize_i64(i), + u64(u) =3D> serializer.serialize_u64(u), + f64(f) =3D> serializer.serialize_f64(f), + CStr(cstr) =3D> { + let s =3D cstr.to_str().map_err(ser::Error::custom)?; + serializer.serialize_str(s) + }, + QList(l) =3D> { + let mut node_ptr =3D unsafe { l.head.tqh_first }; + let mut state =3D serializer.serialize_seq(None)?; + while !node_ptr.is_null() { + let node =3D unsafe { &*node_ptr }; + let elem =3D unsafe { ManuallyDrop::new(QObject::from_= raw(addr_of!(*node.value))) }; + state.serialize_element(&*elem)?; + node_ptr =3D unsafe { node.next.tqe_next }; + } + state.end() + }, + QDict(d) =3D> { + let mut state =3D serializer.serialize_map(Some(d.size))?; + let mut e_ptr =3D unsafe { bindings::qdict_first(d) }; + while !e_ptr.is_null() { + let e =3D unsafe { &*e_ptr }; + let key =3D unsafe { CStr::from_ptr(e.key) }; + let key =3D key.to_str().map_err(ser::Error::custom)?; + state.serialize_key(key)?; + let value =3D unsafe { ManuallyDrop::new(QObject::from= _raw(addr_of!(*e.value))) }; + state.serialize_value(&*value)?; + e_ptr =3D unsafe { bindings::qdict_next(d, e) }; + } + state.end() + } + } + } +} --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818359; cv=none; d=zohomail.com; s=zohoarc; b=LZHuUQcZb/teZ5ysF3f6ukvd5JTKUBAOr6FBZZ3homeaHGsnHOl65TO9O/g21bBaXGMBZq7oOgThtVqrYgiMsBVQMbwGJCjDdh25dRH+Bnb8Sff1CG/wfshcYCHzoWIYuRFAZ2I72pAwh3ccWu9qg42wo6zvz+g7BmCOALXoi9g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818359; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ttSAr3eGwRDYpXQonasNH+X2fnYc35NRwAt0tFm2UtI=; b=Fn1Ghcq5sYfFn6bt38YwPwN9eqimjJcDmLBKrWLyHP7sOymdUPzB3YqcFNhpxZVkHb0OFp1ss9LPS15ykeT0hs6KWW0U5B778ghTD+DOM4LO/HVByiXAxtAJCnalOj6YT+jQvfS7nZ09szimZBiUTK7jOBveWNjZMB06B2yWGFQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818359073564.718139380245; Tue, 26 May 2026 10:59:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw18-0001xp-Sp; Tue, 26 May 2026 13:56:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw17-0001wu-77 for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:37 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw14-0007tc-GT for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:36 -0400 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-25-T-Q3MV6WOA-k_hYdZ3h36g-1; Tue, 26 May 2026 13:56:32 -0400 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-4903dcb32f8so42774925e9.0 for ; Tue, 26 May 2026 10:56:32 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4907eaca94esm1474245e9.8.2026.05.26.10.56.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818193; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ttSAr3eGwRDYpXQonasNH+X2fnYc35NRwAt0tFm2UtI=; b=Xe6P/iUHkMGNIVryIRWP9VBwHQl52tYnD1wQkgtYWTo1QMoTeaS/hheFgys6coIH6CIFNV fVklTiZrAh1OtU56a/6z+FKoOYx6bEkUtuodzL4rjmWSsJKLHPizJDXET8XXvYHAP5u3ff PP7hE7lGeCMozUxuQvZxnk0vJAuFao4= X-MC-Unique: T-Q3MV6WOA-k_hYdZ3h36g-1 X-Mimecast-MFC-AGG-ID: T-Q3MV6WOA-k_hYdZ3h36g_1779818191 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818191; x=1780422991; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ttSAr3eGwRDYpXQonasNH+X2fnYc35NRwAt0tFm2UtI=; b=U5ZqHuqiaArBKwuSCkO+E41cuNKMHPrX3H0pTV6zZuK6d9PFTBiW0IWjO2TWVAp9wh EvVNT8jkUwImqBe63wxblhSU72AQGtpDOW/UPvisO7fGF5WBzQAyrFW2qqrlThWxLKFr jkFUuX8PPA+NI+i9HDkStrC2T/xykiQLP24MadWBlyFO7vjo18YZ1zZW8VS0tScBYLzu WKVYOidoB2tI/UDbAdAb+kBVlO4mmDjTKV5GIqoieOTD+oLjT0Uha7RzBd9On0QQZg39 OoEc9D9as2ptFvPpsJkW30Ez7+yw2i3FTaYxKltRsSpatkMHNjoGZXohLjxOE3wNNlgT NEUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818191; x=1780422991; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ttSAr3eGwRDYpXQonasNH+X2fnYc35NRwAt0tFm2UtI=; b=iI+OhoWL38V15RUT3xUesW68ppMCvsjFIsVumeuceHGUYpQtzM1va98Haj2xovpNo3 D9eGfEQFR5u5KD9ESRv4+9fMtlLHLijBSV3ppjjB6qPrS8iowIjs8TZ4z3KJ9qjZMHki RcP06+1mO1qS8arndTb9AidhQLwcl3yiM0R+62bkLG13U56QRKGsSQwctXqwMSgbsmSP EHGDCcQw/y7hGi+tq60RN8JVPruc7Xrfp7Pu6Wb8SZVurfFO47nFG3aAfbP9iK1h15Ul xNDktXFbL4EZchUbeUN1bpxTpV9wyKYNpZcZTTvKR/rGuyYLb+YE0vDYjf5Ybqw0EeJw 4P6A== X-Gm-Message-State: AOJu0YzLm8EoRIQ13WCHl8jsZbVY0BhGAJzU6Jx7c9QcysGjJtt913By 7fTa2brBeeLIFgiNPBVh7CzijTT3AVvXLn6HF7rTUZVVWWh4x3NTavDPCP3QCgGVFgedKVkLf8/ Vd2wcrOAnIzz9MhJoU/EFw+jh0SqhNcrmbledfoSCzRe5m7e2fpDqvxuSnwyzSYDS7h2seVtK1I fRQGmsHN5DAIFi+0BnefcR5oO1z8Az/pUzR4UtR7OG X-Gm-Gg: Acq92OE8eW7p/1W7PRURQ2z60B+xgIiI7kV+KCWnObMAMuOTmQxy9E4J9bGy/ASt6Rp Di3a/8++ZiTQS13d3MeTrV8T/58hlE/VarejshWGWYlEUi4kCWBH3VN80G7gJ+84hWlbeAUQCdV 1PkX6lKQTs6HfE37rq8wyDmb9oj1DgU847vXqmiIaAXnCZiT+KSle5C9j7p0/ZmLJ1Ay+XdQWVj iVwcmA/6syICE1As/RZbiz26TvgIBJLKM1W9+KhUVb3bE0FzV3aCXcuptSgk0mTr/wALdz1Texp yWRHCRywYepMWB7r1c9J9o/uS00VQn+E6bngKdRcmg2ZGIe/aQdEY3EzOcj/7Rm37t9Op7U4ii7 5AaOTNAVQRNnpU+rDZYKDGmH/vqHP0VizM5ngyuxfRksxbZyfUsk3n4IwVSvuoUcB9nJGvsoxKQ SAEltcurRIkiJ+ejFdwtXuyu6jRIoLaGTqq4fhFw== X-Received: by 2002:a05:600c:4688:b0:48f:e230:80a3 with SMTP id 5b1f17b1804b1-49042ae99afmr325588885e9.33.1779818190876; Tue, 26 May 2026 10:56:30 -0700 (PDT) X-Received: by 2002:a05:600c:4688:b0:48f:e230:80a3 with SMTP id 5b1f17b1804b1-49042ae99afmr325588405e9.33.1779818190280; Tue, 26 May 2026 10:56:30 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com, Zhao Liu Subject: [PATCH v3 04/19] rust/qobject: add Serializer (to_qobject) implementation Date: Tue, 26 May 2026 19:56:03 +0200 Message-ID: <20260526175618.227743-5-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818359994158500 This allows creating QObject from any serializable data structure. Co-authored-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/util/src/qobject/error.rs | 52 +++ rust/util/src/qobject/mod.rs | 4 + rust/util/src/qobject/serializer.rs | 585 ++++++++++++++++++++++++++++ 3 files changed, 641 insertions(+) create mode 100644 rust/util/src/qobject/error.rs create mode 100644 rust/util/src/qobject/serializer.rs diff --git a/rust/util/src/qobject/error.rs b/rust/util/src/qobject/error.rs new file mode 100644 index 00000000000..5212e65c4f7 --- /dev/null +++ b/rust/util/src/qobject/error.rs @@ -0,0 +1,52 @@ +//! Error data type for `QObject`'s `serde` integration + +use std::{ + ffi::NulError, + fmt::{self, Display}, + str::Utf8Error, +}; + +use serde::ser; + +#[derive(Debug)] +pub enum Error { + Custom(String), + KeyMustBeAString, + InvalidUtf8, + NulEncountered, + NumberOutOfRange, +} + +impl ser::Error for Error { + fn custom(msg: T) -> Self { + Error::Custom(msg.to_string()) + } +} + +impl From for Error { + fn from(_: NulError) -> Self { + Error::NulEncountered + } +} + +impl From for Error { + fn from(_: Utf8Error) -> Self { + Error::InvalidUtf8 + } +} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Custom(msg) =3D> formatter.write_str(msg), + Error::KeyMustBeAString =3D> formatter.write_str("key must be = a string"), + Error::InvalidUtf8 =3D> formatter.write_str("invalid UTF-8 in = string"), + Error::NulEncountered =3D> formatter.write_str("NUL character = in string"), + Error::NumberOutOfRange =3D> formatter.write_str("number out o= f range"), + } + } +} + +impl std::error::Error for Error {} + +pub type Result =3D std::result::Result; diff --git a/rust/util/src/qobject/mod.rs b/rust/util/src/qobject/mod.rs index c42b75f3199..c94b2028c1d 100644 --- a/rust/util/src/qobject/mod.rs +++ b/rust/util/src/qobject/mod.rs @@ -6,7 +6,9 @@ =20 #![deny(clippy::unwrap_used)] =20 +mod error; mod serialize; +mod serializer; =20 use std::{ cell::UnsafeCell, @@ -17,6 +19,8 @@ }; =20 use common::assert_field_type; +pub use error::{Error, Result}; +pub use serializer::to_qobject; =20 use crate::bindings; =20 diff --git a/rust/util/src/qobject/serializer.rs b/rust/util/src/qobject/se= rializer.rs new file mode 100644 index 00000000000..08730855731 --- /dev/null +++ b/rust/util/src/qobject/serializer.rs @@ -0,0 +1,585 @@ +//! `QObject` serializer +//! +//! This module implements a [`Serializer`](serde::ser::Serializer) that +//! produces `QObject`s, allowing them to be created from serializable data +//! structures (such as primitive data types, or structs that implement +//! `Serialize`). + +use std::ffi::CString; + +use serde::ser::{Impossible, Serialize}; + +use super::{ + error::{Error, Result}, + QObject, +}; + +pub struct SerializeTupleVariant { + name: CString, + vec: Vec, +} + +impl serde::ser::SerializeTupleVariant for SerializeTupleVariant { + type Ok =3D QObject; + type Error =3D Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.vec.push(to_qobject(value)?); + Ok(()) + } + + fn end(self) -> Result { + let SerializeTupleVariant { name, vec, .. } =3D self; + + // TODO: insert elements one at a time + let list =3D QObject::from_iter(vec); + + // serde by default represents enums as a single-entry object, with + // the variant stored in the key ("external tagging"). Internal t= agging + // is implemented by the struct that requests it, not by the seria= lizer. + let map =3D [(name, list)]; + Ok(QObject::from_iter(map)) + } +} + +pub struct SerializeStructVariant { + name: CString, + vec: Vec<(CString, QObject)>, +} + +impl serde::ser::SerializeStructVariant for SerializeStructVariant { + type Ok =3D QObject; + type Error =3D Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Resu= lt<()> + where + T: ?Sized + Serialize, + { + self.vec.push((CString::new(key)?, to_qobject(value)?)); + Ok(()) + } + + fn end(self) -> Result { + // TODO: insert keys one at a time + let SerializeStructVariant { name, vec, .. } =3D self; + let list =3D QObject::from_iter(vec); + + // serde by default represents enums as a single-entry object, with + // the variant stored in the key ("external tagging"). Internal t= agging + // is implemented by the struct that requests it, not by the seria= lizer. + let map =3D [(name, list)]; + Ok(QObject::from_iter(map)) + } +} + +pub struct SerializeVec { + vec: Vec, +} + +impl serde::ser::SerializeSeq for SerializeVec { + type Ok =3D QObject; + type Error =3D Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.vec.push(to_qobject(value)?); + Ok(()) + } + + fn end(self) -> Result { + // TODO: insert elements one at a time + let SerializeVec { vec, .. } =3D self; + let list =3D QObject::from_iter(vec); + Ok(list) + } +} + +impl serde::ser::SerializeTuple for SerializeVec { + type Ok =3D QObject; + type Error =3D Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleStruct for SerializeVec { + type Ok =3D QObject; + type Error =3D Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + serde::ser::SerializeSeq::end(self) + } +} + +struct MapKeySerializer; + +impl serde::Serializer for MapKeySerializer { + type Ok =3D CString; + type Error =3D Error; + + type SerializeSeq =3D Impossible; + type SerializeTuple =3D Impossible; + type SerializeTupleStruct =3D Impossible; + type SerializeTupleVariant =3D Impossible; + type SerializeMap =3D Impossible; + type SerializeStruct =3D Impossible; + type SerializeStructVariant =3D Impossible; + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + Ok(CString::new(variant)?) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -= > Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_bool(self, _value: bool) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_i8(self, _value: i8) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_i16(self, _value: i16) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_i32(self, _value: i32) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_i64(self, _value: i64) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_i128(self, _value: i128) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_u8(self, _value: u8) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_u16(self, _value: u16) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_u32(self, _value: u32) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_u64(self, _value: u64) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_u128(self, _value: u128) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_f32(self, _value: f32) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_f64(self, _value: f64) -> Result { + Err(Error::KeyMustBeAString) + } + + #[inline] + fn serialize_char(self, _value: char) -> Result { + Err(Error::KeyMustBeAString) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result { + Ok(CString::new(value)?) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + Ok(CString::new(value)?) + } + + fn serialize_unit(self) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result= { + Err(Error::KeyMustBeAString) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + Err(Error::KeyMustBeAString) + } + + fn serialize_none(self) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_some(self, _value: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(Error::KeyMustBeAString) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(Error::KeyMustBeAString) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<= Self::SerializeStruct> { + Err(Error::KeyMustBeAString) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(Error::KeyMustBeAString) + } +} + +pub struct SerializeMap { + vec: Vec<(CString, QObject)>, + next_key: Option, +} + +impl serde::ser::SerializeMap for SerializeMap { + type Ok =3D QObject; + type Error =3D Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.next_key =3D Some(key.serialize(MapKeySerializer)?); + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + let key =3D self.next_key.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let key =3D key.expect("serialize_value called before serialize_ke= y"); + self.vec.push((key, to_qobject(value)?)); + Ok(()) + } + + fn end(self) -> Result { + // TODO: insert keys one at a time + let SerializeMap { vec, .. } =3D self; + Ok(QObject::from_iter(vec)) + } +} + +impl serde::ser::SerializeStruct for SerializeMap { + type Ok =3D QObject; + type Error =3D Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Resu= lt<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeMap::serialize_entry(self, key, value) + } + + fn end(self) -> Result { + serde::ser::SerializeMap::end(self) + } +} + +/// Serializer whose output is a `QObject`. +/// +/// This is the serializer that backs [`to_qobject`]. +pub struct Serializer; + +impl serde::Serializer for Serializer { + type Ok =3D QObject; + type Error =3D Error; + type SerializeSeq =3D SerializeVec; + type SerializeTuple =3D SerializeVec; + type SerializeTupleStruct =3D SerializeVec; + type SerializeTupleVariant =3D SerializeTupleVariant; + type SerializeMap =3D SerializeMap; + type SerializeStruct =3D SerializeMap; + type SerializeStructVariant =3D SerializeStructVariant; + + #[inline] + fn serialize_bool(self, value: bool) -> Result { + Ok(value.into()) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result { + Ok(value.into()) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result { + Ok(value.into()) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result { + Ok(value.into()) + } + + fn serialize_i64(self, value: i64) -> Result { + Ok(value.into()) + } + + fn serialize_i128(self, value: i128) -> Result { + if let Ok(value) =3D u64::try_from(value) { + Ok(value.into()) + } else if let Ok(value) =3D i64::try_from(value) { + Ok(value.into()) + } else { + Err(Error::NumberOutOfRange) + } + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result { + Ok(value.into()) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result { + Ok(value.into()) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result { + Ok(value.into()) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result { + Ok(value.into()) + } + + fn serialize_u128(self, value: u128) -> Result { + if let Ok(value) =3D u64::try_from(value) { + Ok(value.into()) + } else { + Err(Error::NumberOutOfRange) + } + } + + #[inline] + fn serialize_f32(self, float: f32) -> Result { + Ok(float.into()) + } + + #[inline] + fn serialize_f64(self, float: f64) -> Result { + Ok(float.into()) + } + + #[inline] + fn serialize_char(self, value: char) -> Result { + let mut s =3D String::new(); + s.push(value); + Ok(CString::new(s)?.into()) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result { + Ok(CString::new(value)?.into()) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + // Serialize into a vector of numeric QObjects + let it =3D value.iter().copied(); + Ok(QObject::from_iter(it)) + } + + #[inline] + fn serialize_unit(self) -> Result { + Ok(().into()) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result= { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + self.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -= > Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + // serde by default represents enums as a single-entry object, with + // the variant stored in the key ("external tagging"). Internal t= agging + // is implemented by the struct that requests it, not by the seria= lizer. + let map =3D [(CString::new(variant)?, to_qobject(value)?)]; + Ok(QObject::from_iter(map)) + } + + #[inline] + fn serialize_none(self) -> Result { + self.serialize_unit() + } + + #[inline] + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(SerializeVec { + vec: Vec::with_capacity(len.unwrap_or(0)), + }) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + name: CString::new(variant)?, + vec: Vec::with_capacity(len), + }) + } + + fn serialize_map(self, _len: Option) -> Result { + Ok(SerializeMap { + vec: Vec::new(), + next_key: None, + }) + } + fn serialize_struct(self, _name: &'static str, len: usize) -> Result { + self.serialize_map(Some(len)) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + _len: usize, + ) -> Result { + Ok(SerializeStructVariant { + name: CString::new(variant)?, + vec: Vec::new(), + }) + } +} + +pub fn to_qobject(input: T) -> Result +where + T: Serialize, +{ + input.serialize(Serializer) +} --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818352; cv=none; d=zohomail.com; s=zohoarc; b=d1nKIan/pnblu9C6OMkBSPeLpaGGTQMbmDRawstnBiNgvoghCKFhwG2k8Cu7m2BaLQrzb3ubHNEBvI9j3ZwTDtLOHreHh384BGbZG5TiidF+ap4TcyV8c7y3W4+O26g6gkTBnCxvvNuOjOe6iN4lrnXCUUbRJZJVEM1j0fzUMuU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818352; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=NhpMW+defQp1Zy/D4N51kFlexsTA9gX8PHAGBhgbGMA=; b=KykADnD1tTMPZONuw746IqJ5f6lr8CZ4ZrtVdheb09opCy93t0YUx7Srt2SGTVu88sVFwliu6tenURYgtOoci7XLg/7h/a6Z29BGP4MaYXTarxVZVjsg6X8M7XnRni4vG39hl+aws3gKfcVmuEGboU3zG2OBYoVWxdCUpk5dWcA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818352660711.9249481207469; Tue, 26 May 2026 10:59:12 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1D-0001zo-JR; Tue, 26 May 2026 13:56:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1B-0001yo-7S for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:41 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw19-0007w3-B3 for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:40 -0400 Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-630-CX7vTfOFMbqyB5q4N4SaYA-1; Tue, 26 May 2026 13:56:36 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-49043386b3fso40638445e9.3 for ; Tue, 26 May 2026 10:56:36 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490454ac676sm373142235e9.13.2026.05.26.10.56.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818198; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NhpMW+defQp1Zy/D4N51kFlexsTA9gX8PHAGBhgbGMA=; b=I7uhXJfLw2ML/Su1AZ6q6j+3I/tSf/skvHF/dv50UEJ/+r3F09TAQtZFm6R+x5WLCZnHm4 RsBCsYKXzNSZOhWMAedmm47javCzvR6FNJpiN1w3vEkRJdO+hyrhSAjzTsht3SdEhCWr9z Sstw//dNN0+MiZDh4QF5ltN822hiiYU= X-MC-Unique: CX7vTfOFMbqyB5q4N4SaYA-1 X-Mimecast-MFC-AGG-ID: CX7vTfOFMbqyB5q4N4SaYA_1779818195 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818195; x=1780422995; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NhpMW+defQp1Zy/D4N51kFlexsTA9gX8PHAGBhgbGMA=; b=FSBc8v75IESz4FrSuvT0NTkolPBh4HS2eYQ8hlORrAnzkyh7r4glyZ3mUfYTKNh2M3 Nxvsd7AW8Nqv5ZRu2CvcyeSkBPd4awqqbXvmolTgSplWqnjtrzw5NIt89JSp6qnWyEWR XmmAEIx1EqKIiDvBlRj+gcadHIVUtspy80YH7GhJtNV6EfWjzRCuAjqVhJ0J9O+XKYFl rPUOc+gc4zTSID7XrU81IzaybTUP+ENe2bRz4/AiTzUGvJv+nOlenVw881bAxTsUzdSb lQ7f+KusL/OLO/K2hx7hF1k4HBTovjbJLkJ9WOdCXht1JNrQgvG6TxtumZ+ZWkLhI6+o 6nCw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818195; x=1780422995; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=NhpMW+defQp1Zy/D4N51kFlexsTA9gX8PHAGBhgbGMA=; b=sLNwN374ltoM/UWF2937khKbP9F08v5GHQo7cn+Cq1mwJnnW1T7MFg6UGQdaW8s7mE rC/4fWzcMoZY64rEdtQoNDB0fF8b7Rrd2Lksw1o/3AsmBovdTW2iiFqKFpoVeDbu8ZIb qb8oS/S7vqlDjy5m9uGMDGE6ITgLIOeSzIl/bQ5SXuSkeyVzPpS3HgxkhmXAZIgAkryH UqeLmXqm6h+vxIK2LxJLywdj4biQzyh/JL4sS9pPbz0jbIx3TQBRDQiq6hQpfKz6xcjs SO+BzPPlkbYoIB1edKFnnJnCBrVKPoDNn7f8bra7f5V7fJQmpozPdhKI4+Dc0ycv6Lw+ Z62w== X-Gm-Message-State: AOJu0Yy0Kn8cqLPHK/UVEgrYItQauBMkPK70EfEjal0eULdkLS0EFu6i BaouOpStompiPHa7GuG3HRZlj3Km3hDWE6W/wcn5a3AYvHanKEuhSFcZWR9rdQkHXfkrcZWu4q/ PUMUWGtv0ujyk7SnOSTNjcob/V5KlM/Laf/3v8lkpXMMZE+0pXatlcl7Qn84uJcUNTVAz/0kFTG ZLfELrQkaRX7Yo4zPKCRGVabVRxZA5MPDYzKZeNV28 X-Gm-Gg: Acq92OFe+yvwgbKj/YQphSWo3+QCn5gM/yPVVU6UaI7djT0qsRNh9JR7J9ei57DQcdD TR2quHUl0epqF1NJnV31W9uyD7xkzysW6FhPz95NYTA5wI1GC29n3Nz3cIek5hsNZCO8EC3lckL levvUrl4YrJZeacvqXlRviXMFfDh1e53mFx32xT0jK/5zLrPMMwgK9OhjQLNhrdciUHIcYQQIlr 9jLRIJ7YTy4Psl7jBTjAN3JXN/0R15K5z19UqIrjtKrPNKelgCol80xvKE2bMbpt8JIHPRezeVS Ljwc+2dzUqoTquNkpEgn9JutIPlAmPWtjxYJf2WlID7nw7EuuaNa1j99Poa9o8seipKtrhzeMjq xmbiVJO7vsEsgbBRTMlw0uBnkVNNVSRbj4Awy7UrFHtq7l0LU6+Gvhz4EMFeZq7EmcTC6ZFPH3K /hn0j+l/zANplZAtEbg1vkRpZ4ldn3g5qDzg2MSg== X-Received: by 2002:a05:600c:45c9:b0:490:5cb3:e94a with SMTP id 5b1f17b1804b1-4905cb3eb81mr192571835e9.2.1779818195173; Tue, 26 May 2026 10:56:35 -0700 (PDT) X-Received: by 2002:a05:600c:45c9:b0:490:5cb3:e94a with SMTP id 5b1f17b1804b1-4905cb3eb81mr192571345e9.2.1779818194564; Tue, 26 May 2026 10:56:34 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com, Zhao Liu Subject: [PATCH v3 05/19] rust/qobject: add Deserialize implementation Date: Tue, 26 May 2026 19:56:04 +0200 Message-ID: <20260526175618.227743-6-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818353917154100 This allows QObject to be created from any serializable format, for example JSON via serde_json. This is not too useful, since QObjects are produced by C code or by serializing structs, but it can be used for testing and it is part of the full implementation of a serde format. It is relatively simple and similar to the Serializer, just with the extra indirection of a Visitor. Co-authored-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/util/src/qobject/deserialize.rs | 134 +++++++++++++++++++++++++++ rust/util/src/qobject/mod.rs | 1 + 2 files changed, 135 insertions(+) create mode 100644 rust/util/src/qobject/deserialize.rs diff --git a/rust/util/src/qobject/deserialize.rs b/rust/util/src/qobject/d= eserialize.rs new file mode 100644 index 00000000000..3ac1cabbae6 --- /dev/null +++ b/rust/util/src/qobject/deserialize.rs @@ -0,0 +1,134 @@ +//! `QObject` deserialization +//! +//! This module implements the [`Deserialize`] trait for `QObject`, +//! allowing it to be created from any serializable format, for +//! example JSON. + +use core::fmt; +use std::ffi::CString; + +use serde::de::{self, Deserialize, MapAccess, SeqAccess, Visitor}; + +use super::{to_qobject, QObject}; + +impl<'de> Deserialize<'de> for QObject { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> Visitor<'de> for ValueVisitor { + type Value =3D QObject; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Re= sult { + formatter.write_str("any valid JSON value") + } + + #[inline] + fn visit_bool(self, value: bool) -> Result { + Ok(value.into()) + } + + #[inline] + fn visit_i64(self, value: i64) -> Result { + Ok(value.into()) + } + + fn visit_i128(self, value: i128) -> Result + where + E: serde::de::Error, + { + to_qobject(value).map_err(|_| de::Error::custom("number ou= t of range")) + } + + #[inline] + fn visit_u64(self, value: u64) -> Result { + Ok(value.into()) + } + + fn visit_u128(self, value: u128) -> Result + where + E: serde::de::Error, + { + to_qobject(value).map_err(|_| de::Error::custom("number ou= t of range")) + } + + #[inline] + fn visit_f64(self, value: f64) -> Result { + Ok(value.into()) + } + + #[inline] + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + CString::new(value) + .map_err(de::Error::custom) + .map(QObject::from) + } + + #[inline] + fn visit_string(self, value: String) -> Result + where + E: serde::de::Error, + { + CString::new(value) + .map_err(de::Error::custom) + .map(QObject::from) + } + + #[inline] + fn visit_none(self) -> Result { + Ok(().into()) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(deserializer) + } + + #[inline] + fn visit_unit(self) -> Result { + Ok(().into()) + } + + #[inline] + fn visit_seq(self, mut visitor: V) -> Result + where + V: SeqAccess<'de>, + { + // TODO: insert elements one at a time + let mut vec =3D Vec::::new(); + + while let Some(elem) =3D visitor.next_element()? { + vec.push(elem); + } + Ok(QObject::from_iter(vec)) + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + { + // TODO: insert elements one at a time + let mut vec =3D Vec::<(CString, QObject)>::new(); + + if let Some(first_key) =3D visitor.next_key()? { + vec.push((first_key, visitor.next_value()?)); + while let Some((key, value)) =3D visitor.next_entry()?= { + vec.push((key, value)); + } + } + Ok(QObject::from_iter(vec)) + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} diff --git a/rust/util/src/qobject/mod.rs b/rust/util/src/qobject/mod.rs index c94b2028c1d..6920b9d2777 100644 --- a/rust/util/src/qobject/mod.rs +++ b/rust/util/src/qobject/mod.rs @@ -6,6 +6,7 @@ =20 #![deny(clippy::unwrap_used)] =20 +mod deserialize; mod error; mod serialize; mod serializer; --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818385; cv=none; d=zohomail.com; s=zohoarc; b=ddAJ0JdfRrVc+JlCmgPFLMTfpLOsPeYmavkEmAQq1CQ49l9q7JoYjZLhvHsvUL1ym74iRyYLoPOooVvs2R+ryVZYhHoUgYUMTb7D3xkEenWhw6AJBTMXM3fYjEu+OHjBKXoJjPTgaA+IpF2fsL52mVZ7foh+AXGcCDCQSboESR0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818385; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=mK4ewdpRbWjBOdfd9WIfkWHhs6P79cHSH2ERgJE6mCs=; b=VzVjLANSvj5XLD8Nck+vxekOIgykstMmuYm7mFKb2pZxz9UcZua8luolhpEOTiBzCxb+ah+A0XEcqfKQT/wTfoHW05bnlGWuG9yoG0jGPhBZ85jhcz8cbA/8MlVuQ/C9sf2gtdMxynkIOzseCzI7PoHT3m6UE6h8IcQrpKkxtdU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818385466107.22283800255025; Tue, 26 May 2026 10:59:45 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1E-000208-3u; Tue, 26 May 2026 13:56:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1D-0001zU-3j for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:43 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1A-0007wP-Ov for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:42 -0400 Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-428-m4Cq-_1dNNSPt6qtjgMskw-1; Tue, 26 May 2026 13:56:38 -0400 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-4518f777225so7723030f8f.1 for ; Tue, 26 May 2026 10:56:38 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49049973b71sm100496595e9.29.2026.05.26.10.56.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818200; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mK4ewdpRbWjBOdfd9WIfkWHhs6P79cHSH2ERgJE6mCs=; b=XS6GNStRUAZYIelJGQAI2tZQiw9mMTLz+7toEuGH6Sh1YPjWuX1mcVq9NS/aHRAeTt+7Ge X/Ts01YbxSx5dusCiE+b+z4VV8NmkSU5GT0uV02eK018BR+PmvgCM+8uEGifvmtbU04PEH 6Vj8elb5QkUCbCz41XMbXuDhYRwTNz0= X-MC-Unique: m4Cq-_1dNNSPt6qtjgMskw-1 X-Mimecast-MFC-AGG-ID: m4Cq-_1dNNSPt6qtjgMskw_1779818197 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818197; x=1780422997; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=mK4ewdpRbWjBOdfd9WIfkWHhs6P79cHSH2ERgJE6mCs=; b=B50xsXAjR43ivxvM45nBQ3mPLZGcivw1ZPq29+/FuA86MWysIevnzxYnLSjuuIBeLY jMomj8xUI3g45sXANYSuoTJ1po+hcc/5r+pvFrane/WURniQP+2Odz6h8gTUy/LawMyX JcwXQ1B+GAx0wQMS2SbiE9lq6lFiJ9z1l7XEMuxlpRLZUfwdcsEErrpKEuSgzQOjUycj 50SbGxaJIa2KFASUiqwiU/BFzqQM6EMEjo2QKmG22kL9qqCrGGcDkPPDVimGJpDkXfYH 2XvLmXWoNI9F9f1JjLdBuoig1TTnGrW/BRTvrtUj13y3ljr2BbLtjs0DH4ucNr+H9kCo kt8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818197; x=1780422997; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=mK4ewdpRbWjBOdfd9WIfkWHhs6P79cHSH2ERgJE6mCs=; b=IYMp6Ezq8d8gTMts0Omy+AaMKf/iyrg/sxbd5ZLEs8OVL35Pn57vLSk7GpayrzubhV RQc0FCgDk8ZNOKtNkieoYQhsP1JXUtCz2+2wtVHpYHPEaOn/K1L3hsRYgdyA5YEnz9AP nSTKBA6MtgQ0XveX0GqB8cMRawpc/h7G9+Yn6g+DcSlGQz2At+5yES7KB8fti5K815Ms lH22OoxxtjP8jXD58KFTLgELZ5A4+C9lDWb57M/+xFNZvYOrB62pMr4tOQgPnYkos75p hlSA6lW+lp019YeHNCElXo+QVqRcMBu/2+d7m6lxaAPU/V09s3ZNhhjyBJbUBopb7Ioq U1Aw== X-Gm-Message-State: AOJu0YxFqfIYzpF07wucPB4hX2H6fKmzskqoJfmQmf3LM3tWfhPTnNjq BLN6RAd51m+SQyL+uSR740AJZyGuOjyN1aN/Df76Z68Te2PUEb06SAd4ezn5c+58QC4WnYHHjrk tRu/Mh1gtH2FUfxipQHERrwY0zWmjcCKbmzVHOwereTzqdXiaxh7bjiVxD3ymSwfvufghW14Gm0 Rq5m6COG/DF2o/+e3e8+p6W8IFRA7txpy7hNK+99gb X-Gm-Gg: Acq92OGirBBYmCQkc2JGEuANNRlBT3edFkwp1hLgNJPwaRGgrQg7CkoubzDHqYXTmxs XflVmmZF92XJ1noPh5CCkN/Yb3FWxft//bV1QtuR3lC3qwKH9eXTjMo/yu6ZuVsjY8qbhY86alt 9Rr31nLbP9EINvazlmvmFDalUnAiGhxwbBHWc0gk4rPL3gSmT2BOwRvnGmyxIFYL4e7SozxmmSx tv5BUWm9MzLgTjjKhRp9LrGqK2q70ZvVlPwE3N+C52Oa+ZNN6Y2GRLPC1cvpqMBle7fiR+JnFhh taYPQ787kLF3L2+NhOY5lWrYxcb2FKMDgDParERKXn2Laye8krHvyQWgf7NJogQzw7bOG1ICI7s bGetmAt9VhmNYrJfYSYNBKDeHPjxn+k3MlaPFSG1G/uhPXLO9vOievTwOQBQzWkziy6V07WAB98 ntR1ESXSIpBQ7Z9a+WSd/fHJR+M3Y= X-Received: by 2002:a05:600c:4ecc:b0:490:3d62:f5e1 with SMTP id 5b1f17b1804b1-490426cbba2mr328828665e9.22.1779818196875; Tue, 26 May 2026 10:56:36 -0700 (PDT) X-Received: by 2002:a05:600c:4ecc:b0:490:3d62:f5e1 with SMTP id 5b1f17b1804b1-490426cbba2mr328828265e9.22.1779818196276; Tue, 26 May 2026 10:56:36 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com, Zhao Liu Subject: [PATCH v3 06/19] rust/qobject: add Deserializer (from_qobject) implementation Date: Tue, 26 May 2026 19:56:05 +0200 Message-ID: <20260526175618.227743-7-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818386041158500 This allows creating any serializable data structure from QObject. The purpose of all the code is to typecheck each variant in the serde data model and check that it's one of the corresponding QObject data types. Co-authored-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- docs/devel/rust.rst | 1 + rust/util/src/qobject/deserializer.rs | 371 ++++++++++++++++++++++++++ rust/util/src/qobject/error.rs | 8 +- rust/util/src/qobject/mod.rs | 2 + 4 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 rust/util/src/qobject/deserializer.rs diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index 67ea84539a2..ebfa6c21883 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -162,6 +162,7 @@ module status ``util::error`` stable ``util::log`` proof of concept ``util::module`` complete +``util::qobject`` stable ``util::timer`` stable =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/rust/util/src/qobject/deserializer.rs b/rust/util/src/qobject/= deserializer.rs new file mode 100644 index 00000000000..b0f8aa23773 --- /dev/null +++ b/rust/util/src/qobject/deserializer.rs @@ -0,0 +1,371 @@ +//! `QObject` deserializer +//! +//! This module implements a [`Deserializer`](serde::de::Deserializer) that +//! consumes `QObject`s, allowing them to be turned into deserializable da= ta +//! structures (such as primitive data types, or structs that implement +//! `Deserialize`). + +use std::ffi::CStr; + +use serde::de::{ + self, value::StrDeserializer, DeserializeSeed, Expected, IntoDeseriali= zer, MapAccess, + SeqAccess, Unexpected, Visitor, +}; + +use super::{ + error::{Error, Result}, + match_qobject, QObject, +}; +use crate::bindings; + +impl QObject { + #[cold] + fn invalid_type(&self, exp: &dyn Expected) -> E + where + E: serde::de::Error, + { + serde::de::Error::invalid_type(self.unexpected(), exp) + } + + #[cold] + fn unexpected(&self) -> Unexpected<'_> { + match_qobject! { (self) =3D> + () =3D> Unexpected::Unit, + bool(b) =3D> Unexpected::Bool(b), + i64(n) =3D> Unexpected::Signed(n), + u64(n) =3D> Unexpected::Unsigned(n), + f64(n) =3D> Unexpected::Float(n), + CStr(s) =3D> s.to_str().map_or_else( + |_| Unexpected::Other("string with invalid UTF-8"), + Unexpected::Str), + QList(_) =3D> Unexpected::Seq, + QDict(_) =3D> Unexpected::Map, + } + } +} + +fn visit_qlist_ref<'de, V>(qlist: &'de bindings::QList, visitor: V) -> Res= ult +where + V: Visitor<'de>, +{ + struct QListDeserializer(*mut bindings::QListEntry, usize); + + impl<'de> SeqAccess<'de> for QListDeserializer { + type Error =3D Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: DeserializeSeed<'de>, + { + if self.0.is_null() { + return Ok(None); + } + + let e =3D unsafe { &*self.0 }; + // increment the reference count because deserialize consumes = `value`. + let value =3D unsafe { QObject::cloned_from_raw(e.value.cast_c= onst()) }; + let result =3D seed.deserialize(value); + self.0 =3D unsafe { e.next.tqe_next }; + self.1 +=3D 1; + result.map(Some) + } + } + + let mut deserializer =3D QListDeserializer(unsafe { qlist.head.tqh_fir= st }, 0); + let seq =3D visitor.visit_seq(&mut deserializer)?; + if deserializer.0.is_null() { + Ok(seq) + } else { + Err(serde::de::Error::invalid_length( + deserializer.1, + &"fewer elements in array", + )) + } +} + +fn visit_qdict_ref<'de, V>(qdict: &'de bindings::QDict, visitor: V) -> Res= ult +where + V: Visitor<'de>, +{ + struct QDictDeserializer(*mut bindings::QDict, *const bindings::QDictE= ntry); + + impl<'de> MapAccess<'de> for QDictDeserializer { + type Error =3D Error; + + fn next_key_seed(&mut self, seed: T) -> Result> + where + T: DeserializeSeed<'de>, + { + if self.1.is_null() { + return Ok(None); + } + + let e =3D unsafe { &*self.1 }; + let key =3D unsafe { CStr::from_ptr(e.key) }; + let key_de =3D StrDeserializer::new(key.to_str()?); + seed.deserialize(key_de).map(Some) + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + if self.1.is_null() { + panic!("next_key must have returned None"); + } + + let e =3D unsafe { &*self.1 }; + // increment the reference count because deserialize consumes = `value`. + let value =3D unsafe { QObject::cloned_from_raw(e.value) }; + let result =3D seed.deserialize(value); + self.1 =3D unsafe { bindings::qdict_next(self.0, self.1) }; + result + } + } + + let qdict =3D (qdict as *const bindings::QDict).cast_mut(); + let e =3D unsafe { bindings::qdict_first(qdict) }; + let mut deserializer =3D QDictDeserializer(qdict, e); + let map =3D visitor.visit_map(&mut deserializer)?; + if deserializer.1.is_null() { + Ok(map) + } else { + Err(serde::de::Error::invalid_length( + unsafe { bindings::qdict_size(qdict) }, + &"fewer elements in map", + )) + } +} + +fn visit_qnum_ref<'de, V>(qnum: QObject, visitor: V) -> Result +where + V: Visitor<'de>, +{ + match_qobject! { (qnum) =3D> + i64(n) =3D> visitor.visit_i64(n), + u64(n) =3D> visitor.visit_u64(n), + f64(n) =3D> visitor.visit_f64(n), + _ =3D> Err(qnum.invalid_type(&"number")), + } +} + +macro_rules! deserialize_number { + ($method:ident) =3D> { + fn $method(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visit_qnum_ref(self, visitor) + } + }; +} + +impl<'de> serde::Deserializer<'de> for QObject { + type Error =3D Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + () =3D> visitor.visit_unit(), + bool(v) =3D> visitor.visit_bool(v), + i64(n) =3D> visitor.visit_i64(n), + u64(n) =3D> visitor.visit_u64(n), + f64(n) =3D> visitor.visit_f64(n), + CStr(cstr) =3D> visitor.visit_str(cstr.to_str()?), + QList(qlist) =3D> visit_qlist_ref(qlist, visitor), + QDict(qdict) =3D> visit_qdict_ref(qdict, visitor), + } + } + + deserialize_number!(deserialize_i8); + deserialize_number!(deserialize_i16); + deserialize_number!(deserialize_i32); + deserialize_number!(deserialize_i64); + deserialize_number!(deserialize_i128); + deserialize_number!(deserialize_u8); + deserialize_number!(deserialize_u16); + deserialize_number!(deserialize_u32); + deserialize_number!(deserialize_u64); + deserialize_number!(deserialize_u128); + deserialize_number!(deserialize_f32); + deserialize_number!(deserialize_f64); + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + () =3D> visitor.visit_none(), + _ =3D> visitor.visit_some(self), + } + } + + fn deserialize_enum( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + CStr(cstr) =3D> visitor.visit_enum(cstr.to_str()?.into_deseria= lizer()), + _ =3D> Err(self.invalid_type(&"string")), + } + } + + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V= ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + bool(v) =3D> visitor.visit_bool(v), + _ =3D> Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + CStr(cstr) =3D> visitor.visit_str(cstr.to_str()?), + _ =3D> Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + CStr(cstr) =3D> visitor.visit_str(cstr.to_str()?), + QList(qlist) =3D> visit_qlist_ref(qlist, visitor), + _ =3D> Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + () =3D> visitor.visit_unit(), + _ =3D> Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -= > Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + QList(qlist) =3D> visit_qlist_ref(qlist, visitor), + _ =3D> Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + QDict(qdict) =3D> visit_qdict_ref(qdict, visitor), + _ =3D> Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match_qobject! { (self) =3D> + QList(qlist) =3D> visit_qlist_ref(qlist, visitor), + QDict(qdict) =3D> visit_qdict_ref(qdict, visitor), + _ =3D> Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } +} + +pub fn from_qobject(value: QObject) -> Result +where + T: de::DeserializeOwned, +{ + T::deserialize(value) +} diff --git a/rust/util/src/qobject/error.rs b/rust/util/src/qobject/error.rs index 5212e65c4f7..2d7c180187a 100644 --- a/rust/util/src/qobject/error.rs +++ b/rust/util/src/qobject/error.rs @@ -6,7 +6,7 @@ str::Utf8Error, }; =20 -use serde::ser; +use serde::{de, ser}; =20 #[derive(Debug)] pub enum Error { @@ -23,6 +23,12 @@ fn custom(msg: T) -> Self { } } =20 +impl de::Error for Error { + fn custom(msg: T) -> Self { + Error::Custom(msg.to_string()) + } +} + impl From for Error { fn from(_: NulError) -> Self { Error::NulEncountered diff --git a/rust/util/src/qobject/mod.rs b/rust/util/src/qobject/mod.rs index 6920b9d2777..76b167104d1 100644 --- a/rust/util/src/qobject/mod.rs +++ b/rust/util/src/qobject/mod.rs @@ -7,6 +7,7 @@ #![deny(clippy::unwrap_used)] =20 mod deserialize; +mod deserializer; mod error; mod serialize; mod serializer; @@ -20,6 +21,7 @@ }; =20 use common::assert_field_type; +pub use deserializer::from_qobject; pub use error::{Error, Result}; pub use serializer::to_qobject; =20 --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818232; cv=none; d=zohomail.com; s=zohoarc; b=nL83HsHFH5px+1Yi+9+nsIrYRr5o3da9KJ4keidrqQh0MwaIKe3O9e6YnRmHuP9NX7seEDvaa01YNk7NxT6WbZoJXGxfRzEHSJNvViJDEOe73eghVI7KcoGDG6tHLksMy2LEErGhbM/rggcFXAKZkAa3oB16jybLavo0mcPS3PU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818232; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=IwejE0qUh6l3AKjAZStBy9OZpi/ahgfNspmEiwXOJAI=; b=WyhOrm9iEZvS0hlaBWZpDrrDhdEO+cOtG4IqbaF2zAxGQ3J22wSi2/jD+vASaLV11WSElzo0JwASViYdOLwM8MEY1vrEIgm5oR13k1wkmKIvHEkw797zoSXKWW6Gw4HZmwh0Viyx3locw56HbPnSBkk2u2sZxO3LkmjVqz/FXak= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818232306657.8369194929876; Tue, 26 May 2026 10:57:12 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1F-00021K-Te; Tue, 26 May 2026 13:56:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1E-00020N-JH for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:44 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1C-0007wf-Gx for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:44 -0400 Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-537-P6LOR12FNTaFfG0KmkeVTg-1; Tue, 26 May 2026 13:56:40 -0400 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-43d789cebcfso7464757f8f.1 for ; Tue, 26 May 2026 10:56:40 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6c9de2dsm35996346f8f.4.2026.05.26.10.56.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818201; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IwejE0qUh6l3AKjAZStBy9OZpi/ahgfNspmEiwXOJAI=; b=Qup/mtKWGXtdjqMNGnKg7Petgb13KedHO45bbKA2mLVM5/ZS8D0HeCIOyD6SMmbkyXOI+p gLbCS9au4JtrPlZ4kp8Jf4QbP2l/N6aQLTCx9yczpbghZp+AzIeWRREUa9eByi536JWwxd OSiIL+Pgk6hodDnWj8bhI4gCLInjyE4= X-MC-Unique: P6LOR12FNTaFfG0KmkeVTg-1 X-Mimecast-MFC-AGG-ID: P6LOR12FNTaFfG0KmkeVTg_1779818199 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818199; x=1780422999; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IwejE0qUh6l3AKjAZStBy9OZpi/ahgfNspmEiwXOJAI=; b=PsqCKXkazDa9I9QO6ox4EXcfc+e2aKf16NYpREIbRT2Rcjk6+BLKMv1nI2lpFfP/GC 266O1xjo0Jat4329b1Hygxk1VL8iQ2NPFrJOV5M7ru+PXQe+7HnF/zLNYh498LfmHOGv oS3ulhLSLUTzKq8JQUQkzrszDq/sSO4VbnQO3VS7/Rk/nmED7cgbCMJ2KwjnsYVM/ZHd /hd22yvgdZkIf8JlMz95AjmdwKVaqUX4Zh9QqcBbOBSHBtYXLGvnDwJ2jsKULcR0sFHM lbVQLpmtdu42MJwICPid/ADm77Bc56QWT70aCTsS27+mw02dI0ipF5CNiB2Z4L4DJUmU TckA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818199; x=1780422999; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=IwejE0qUh6l3AKjAZStBy9OZpi/ahgfNspmEiwXOJAI=; b=hXwIwg+yVBeQhYJKoXKpTGW5o7hMSWBEcha8reXWqJtQEFm7oGoAEMJFA96EJ1uSvT bCOIxLejcsHZMyuaXuqdnVB8t+36SK5vdRIBBmblb86VZ2oUTYEufRe8dN03xlGKARVH 6Ul/lNruic3p4dqkZ0hRBGLxq31LBT6tl4qHMTpQoFAoNB9zYO1iHl3gnqaakGxcm3c2 NE3P0MYvd1vXNYP0250/3maQemq5HAmQ+bpDwZw9yf2NbdDtC6XqbaZmkX/mGzoIQBg9 7p4yKhSrERiKjtZLmjF5d8PUr8zOmPlUiJo7pxmAv0sP+mqQJR3dcf68qw/9wxCSNKfY Ejjg== X-Gm-Message-State: AOJu0Yyw4vCh5cKR3BAbzbPAnmBwJ6Yyq7gzrbsFrHYI0xR42WX6J8km OUzmVoRJ6CBCQ06PfuUMEe2lMwDh7B0ZoPrwOZCaM3ilKwRXN0AVzNKyeuVwGbcCSRJQGVuaLf/ Q1yWbgHtJ/lQ98L/5kIVd8gtwbHSXvqORXVWmvxvUBIz851g2KlERW+ApHAfF5QpKeg2knzmLCX oHpQdB4EdrOSdRfvm5GnrysfXplO+6ykh27EweqaJb X-Gm-Gg: Acq92OH/Ioka7f6UE8/5x7HYmAfNjkLUtJQDQsm+LBEOqsbvgZGctntb6GCxulEqgfN 377LsThbn5GPLSyGFpkoAgdCMTQlwcUzx4EUqYrEGIOtXf+zYSwrjE/+M3MuGjhjVVnxA0Knw1a RjQ2uHddZbd1//dfdSB3di5gs3sgs17Io/HW5X6aHnOKfsusVTGaWTg73qh39cOqtu0CyCQPUv/ ZVoyZbsSvpFgHPqlLM/2N4DfaO1rbWKroAWMIeK/q21yyxoi+TZgQ4iFMGlB8CDxYKrSIMioU2j HodjLxF3SNRw3+ee/ifbjQu1m+c6+xeCQMHYdMtidPfw1GolMzpZt5u9vYnuMIwIR37mOobpjWz qNu/ZFiCzVoJUKg0XsbFd8woQWWKWXfIGxaBSiJq9FtA+yH0Me94mN8VWS7ezEY/OQL21Pf+Ftd Ir4MN11Vo73OTvZxDi5YhzYjuh/fc= X-Received: by 2002:a05:6000:26c4:b0:45e:739b:2750 with SMTP id ffacd0b85a97d-45eb30ec2e2mr30809568f8f.9.1779818199393; Tue, 26 May 2026 10:56:39 -0700 (PDT) X-Received: by 2002:a05:6000:26c4:b0:45e:739b:2750 with SMTP id ffacd0b85a97d-45eb30ec2e2mr30809523f8f.9.1779818198846; Tue, 26 May 2026 10:56:38 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 07/19] rust/qobject: add from/to JSON bindings for QObject Date: Tue, 26 May 2026 19:56:06 +0200 Message-ID: <20260526175618.227743-8-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818235148158500 These are used by tests. However it could even be an idea to use serde_json + transcoding and get rid of the C version... Co-authored-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Paolo Bonzini --- rust/util/src/qobject/mod.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/rust/util/src/qobject/mod.rs b/rust/util/src/qobject/mod.rs index 76b167104d1..d2dde9ba0f1 100644 --- a/rust/util/src/qobject/mod.rs +++ b/rust/util/src/qobject/mod.rs @@ -23,6 +23,7 @@ use common::assert_field_type; pub use deserializer::from_qobject; pub use error::{Error, Result}; +use foreign::prelude::*; pub use serializer::to_qobject; =20 use crate::bindings; @@ -114,6 +115,22 @@ fn refcnt(&self) -> &AtomicUsize { let qobj =3D self.0.get(); unsafe { AtomicUsize::from_ptr(addr_of_mut!((*qobj).base.refcnt)) } } + + pub fn to_json(&self) -> String { + let qobj =3D self.0.get(); + unsafe { + let json =3D bindings::qobject_to_json(qobj); + glib_sys::g_string_free(json, glib_sys::GFALSE).into_native() + } + } + + pub fn from_json(json: &str) -> std::result::Result { + let c_json =3D std::ffi::CString::new(json)?; + unsafe { + crate::Error::with_errp(|errp| bindings::qobject_from_json(c_j= son.as_ptr(), errp)) + .map(|qobj| QObject::from_raw(qobj)) + } + } } =20 /// Rust equivalent of the C `QOBJECT` macro; for internal use only, becau= se --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818238; cv=none; d=zohomail.com; s=zohoarc; b=jBGM9q/nsB1Wi7hkssmhgS5jNAlsstsGVbCX3T1UsyNYAQTxZaAL36mehAnJ1fK50R7izLjQWhrqBcoz5IKm4oeqANlCQkhMYBE2gzTXrDwYX0ZWsAznF8WWJhCmLKsx3bYWZvvD4fwu75MyDcXSLVmIfRcSWa03ZuAg6qOf3b0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818238; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=GGNiVyk3smt3QCBdx3Hb8LIxSZAyBf2ULYTGIW9VfTc=; b=ZiXsqCVo+x3Hwx8IOqEq/+GzgOEuA9us3KgpUEuacXAFQ27kDtD3Pk4gL4kI951ZMbon6qRvYWRpEImUWNj3UwwRdehJ05T4T7J1MPTXQYG6cK7hDyZquaUWYUP2r6+Uozp1oza+oQKP5kxO9Lyu8QHRQ+HPyOhbtRTME6p7ILE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818238015161.43159976260517; Tue, 26 May 2026 10:57:18 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1I-00022P-SD; Tue, 26 May 2026 13:56:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1H-00021P-2p for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:47 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1E-0007xN-S5 for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:46 -0400 Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-58-dkaBYBsLN9irGJoVyTBkeQ-1; Tue, 26 May 2026 13:56:42 -0400 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-45aeac88af4so8810858f8f.3 for ; Tue, 26 May 2026 10:56:42 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490454a0b9asm336792355e9.11.2026.05.26.10.56.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818204; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GGNiVyk3smt3QCBdx3Hb8LIxSZAyBf2ULYTGIW9VfTc=; b=C3p1jxzkKID7oQ1ddQA+O6mU0xMTbZA0CqU5zH5t6ivQZ+x/Nd7sgGn3gzIRPIyWchjHTv yEQvKo9SsDApbeCV/nIFoQJkxkfVuVAEHvHXkw64J99JVr7N0HChwmmw6gGLuttiXG6FDO hzVKcIoNwXR5bb13PoEtsovn3Q/47Og= X-MC-Unique: dkaBYBsLN9irGJoVyTBkeQ-1 X-Mimecast-MFC-AGG-ID: dkaBYBsLN9irGJoVyTBkeQ_1779818201 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818201; x=1780423001; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GGNiVyk3smt3QCBdx3Hb8LIxSZAyBf2ULYTGIW9VfTc=; b=U1g1rHZ0QHYDRTdYdFrG4+1KQDCKWnu6xVhUn1Gh6MsakXK8AHyQ2GUqeSkL5aIJV4 MNeLgdeEaPtY0oZiKzAVCBbcTtyNs50gUEojrn5kCSHZJJYU2TBH/iIz1DXa1OOOpcGj yVbbdwcB1V8zbOl9+3RJ0bK4RDAxF+16iCnNnMonZlERWuhvfILA2kCVBDBdXz7hl1Tn BD8LUFt+kZxFvFepLVngf/KK7vuDu8pOmePt6W4Ngj81IzY+mCEwNdR7x96MUjPJ5zW9 QNkoquP0IQ29+PPV3ANlCXH5gzlo7ig/b+1AfYP51wGiMzZfnNE5HPVEnHlsj5tDql1J DLlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818201; x=1780423001; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=GGNiVyk3smt3QCBdx3Hb8LIxSZAyBf2ULYTGIW9VfTc=; b=YoXpV5QYOtWu99C/Qu/Jy2B3nRddUGR/EbtOrT2AfEIe+mj3895mbz53aedXe5+Czw P4rTseLH1Dqq2aWaz9sEDh5o1GWQocsJURHsecIJy7qUjx3dt9kpBJBAoha+sPJJHsVm pvPGdqXVo13yaVkYldXTt+kq81ij/WmsCps5IsIpiaHTyUQCNWI35hdSUGeKvLyifU9Q GoUei2PAxB+tPkEWTrYfZwwyTSCOFnP9X7B4zNnl2vsUEp/Q67Nitqa84X+EHs/Ssz9r hB+DSjMY/hT+r+6KITAGwmCCyJ68LNxvxpUwpsZ/p1kRdJwDCbHEfqhiEkEFA30LQ9/U TqfQ== X-Gm-Message-State: AOJu0YxlHJPq5PxpVqb6cMr5IKx7EJS0o80qrx1ovyZ82OihVhCZF137 5ooojXLIb5AIhCca5udMKYC/84X2geIHxpyxBjDT+/vF0Su2olv8Fxn2rF6pmvvK+UXKWeVCSIK CCmw4qa+++bw8CE3b0mI3UsAHw8iorxXQQYYl1o1L7P6eLQBh6TDMt9CU7AKzLqa6yyehUEgm4V DbbXA8YPWFE8o+GTCkYzRJM5yDaaALD89LA9Wp2iQc X-Gm-Gg: Acq92OE9JzLIwWWR9TlKnSFlsXLZYvNVnftRicK7RGN9dF0j35Tfjk9k7blv6DmMnzu fSyFgM0H9KpHLfHCjAu0Quj0L3Cd9/PEnE4QIxeJ7T3359gLNCBdBWS0aYmGZPVimjt3+cO4cbd KWg9KT8H7+fXbGergsoxkQho+8KgSW8LT4s4U8bShY+IyMJvL0Adk5KO7e5VfKvwtSxWYpUG+vp 6UGbntu2ftMjPPFtSSLBxAIYlvdJmv/uF2UPaTFNqagCkHSbbTtooXTOjCODuyoHskHFsqWOE6J 5jixzHP/wgrQdB4z8MabjBWSp+JX/aMtxliTcu7YRFEbaaSnx3aJcELevudq1x9FOree7n+gl5A 2Mk1VozD+8nHOJd6VYwb5YeGfcQCZrnNMR6F9SBj0IDzkOZcV64STkEuKGc9aDp09ruIGSoIcfR gz2zKJiI93g430oW8fc1ysf2frOxg= X-Received: by 2002:a05:600c:a402:b0:486:fd5c:2b35 with SMTP id 5b1f17b1804b1-490426adf66mr270778695e9.13.1779818201458; Tue, 26 May 2026 10:56:41 -0700 (PDT) X-Received: by 2002:a05:600c:a402:b0:486:fd5c:2b35 with SMTP id 5b1f17b1804b1-490426adf66mr270778305e9.13.1779818201028; Tue, 26 May 2026 10:56:41 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 08/19] rust/qobject: add Display/Debug Date: Tue, 26 May 2026 19:56:07 +0200 Message-ID: <20260526175618.227743-9-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818240227154100 From: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Paolo Bonzini --- rust/util/src/qobject/mod.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/rust/util/src/qobject/mod.rs b/rust/util/src/qobject/mod.rs index d2dde9ba0f1..3e22dc8bb3f 100644 --- a/rust/util/src/qobject/mod.rs +++ b/rust/util/src/qobject/mod.rs @@ -12,6 +12,7 @@ mod serialize; mod serializer; =20 +use core::fmt::{self, Debug, Display}; use std::{ cell::UnsafeCell, ffi::{c_char, CString}, @@ -272,6 +273,33 @@ fn drop(&mut self) { } } =20 +impl Display for QObject { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // replace with a plain serializer? + match_qobject! { (self) =3D> + () =3D> write!(f, "QNull"), + bool(b) =3D> write!(f, "QBool({})", if b { "true" } else { "fa= lse" }), + i64(n) =3D> write!(f, "QNumI64({})", n), + u64(n) =3D> write!(f, "QNumU64({})", n), + f64(n) =3D> write!(f, "QNumDouble({})", n), + CStr(s) =3D> write!(f, "QString({})", s.to_str().unwrap_or("ba= d CStr")), + QList(_) =3D> write!(f, "QList"), + QDict(_) =3D> write!(f, "QDict"), + } + } +} + +impl Debug for QObject { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let val =3D self.to_string(); + f.debug_struct("QObject") + .field("ptr", &self.0.get()) + .field("refcnt()", &self.refcnt()) + .field("to_string()", &val) + .finish() + } +} + macro_rules! match_qobject { (@internal ($qobj:expr) =3D> $(() =3D> $unit:expr,)? --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818307; cv=none; d=zohomail.com; s=zohoarc; b=O//giRtkzrtsDSSz9tJ8wbCOcnBV6sNGJ4OkzehCO3joGFkh0Hkfi7x1dL03bwQtkA+eYxAyHzFj68wXQ9f+KU/MiILQdgX2G8JWHUg1Yjq51gmn1pgccK9IQcym3Mg5grblVON51vrHKQuzNZZ9HSMbqquYTqDtPTSWjaL4oZQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818307; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=+AGiBNwzTm1U9cZQLheRtuzZRE/8QtBdPokO2fQmR6g=; b=l70tJEn7N5HqrQbBLr3DIzWHxPtsz+VC8XhLAeZhNJy9oaLOdB76TK3FlpGDn/yDijyLK+XrNGy9tJHggRWRAKjB/x5hU2m1xldSiddmnPXBhtAGnY/iZEh8y1KNNBf7SVJIpE+Wz4KUHc177DM/LVQt0TR7/L+KfxbsrYmLhdY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818307386137.86101762225746; Tue, 26 May 2026 10:58:27 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1O-00025V-22; Tue, 26 May 2026 13:56:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1L-00024G-UZ for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:51 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1K-0007y4-01 for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:51 -0400 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-446-QHgF-NfiOA2LBkwo-nG82g-1; Tue, 26 May 2026 13:56:46 -0400 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-4411a2c034fso9936558f8f.3 for ; Tue, 26 May 2026 10:56:46 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6d4903bsm34573469f8f.21.2026.05.26.10.56.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818209; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+AGiBNwzTm1U9cZQLheRtuzZRE/8QtBdPokO2fQmR6g=; b=LnvqHygsd1jyohO4TRyGSHus+mrHAmkd54UNOSJovnQJ9t/ch9sfaM4oTYyObJzSI8s9Ja Zvo0Uw6wRlPM6MG1x2RG+TwHmv1J5LewQJWR+jd/bKpzjq66OPyGNf5rrft/VSbutR8yHi yJTdSJwunyTq0izKwLszKl83zhvEomg= X-MC-Unique: QHgF-NfiOA2LBkwo-nG82g-1 X-Mimecast-MFC-AGG-ID: QHgF-NfiOA2LBkwo-nG82g_1779818206 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818205; x=1780423005; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+AGiBNwzTm1U9cZQLheRtuzZRE/8QtBdPokO2fQmR6g=; b=Iu0XRWMuU71By9Iw040a8/ZC+koqyrPXgcVJv7Z41mt862CIq5dzJkWGPL/t4q0gcF 6wHKQMRk0TxE7Pql+TdvtRvvec7LZIi9Eux6SxXUo6kVoIhia1vzbEdFUMz7YztqxYBC GsnDlrXAxWAuRLOKEi2tFlR0u+ONkOLOnDsLv72rMCreZpF6WrqZFp4Mhcp9X5Pjoz6W 8uPitjScbqCfT8U3UL5d/Sf23eQ8yLG+fnlxOwGvZdtFkZ3QHze/4pAhbsXkine/Fflt 888uthe116uULOahSXS3FIfHLmn37DmhMXLCaLUTKEKcPjSQXkiwQLjd5CrnlfV9vDPL uBWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818205; x=1780423005; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=+AGiBNwzTm1U9cZQLheRtuzZRE/8QtBdPokO2fQmR6g=; b=oVQt7JPDWXKuhEXInNSoKU7K5tugI8twU0m2CceCu/Doj0s+EbTCogPpri3hra0516 tWCvkixzVntmgXU1SdEG1588jlZzD03I+CZZJrFT0nB1sGbQHJQzm9FcgCwtPmHi5wEn t1eCMRnAdTjrVvF5iGWOSA0ob20P93JwrawENDZyVOuRgpZ+Ms8fWjOtUF/JCeTeKJYl KXWONb+c0O+DQSx6BYQCge5owHFd7oPoAcRRttSCTRGJrwQ/IgNAj/MnH3xnJTiC4X3H 0OCVe5tflGhTyVi5OvLtI/+d5/gNCdoDwkO5Ra7B/21c+a9kQVsPFfVFNNgR0RwIixR4 S9iw== X-Gm-Message-State: AOJu0YwQrghOMN4W0Rxxp1nJA7b5xmmy9r6LiM6POSmGJKn/igydsiGL wudYhqlQraskAoBZhTGy0z65jVrR1wI+XfiJOiJX8/xqRrwkUeJ22SKVCikPNqxcaBORPrmYSn2 bA3xxQkroCFXjEfWgchpAOOXLd0U36in9uVSLni/0Nll6T0HraU3VxI+GBuJDmSvHoXsY5KtpUw ZmpA7ubLl2fLi1CGVKMBxl53Mq05SHdRnqEiU7hiR2 X-Gm-Gg: Acq92OGp0W+gC8b0AO8f43UmaY+934Srf/D2VuQq7KvngZ9Vh7zltGtsX/ERFOoFGRb guZR/mSZgHyb0lCiQx8eT51COS/2kqxqvu6RG7xPLhDzwSoWuLV8vDnhO6oOVsWBggjcTECSbHU 3wiOwRadYkPdehX6RIrjhyjQiTJPpH1Tqivzvf1LPhP8CF9XniJNtA18CC5HZzNxcdh0d8f0I9q d9aG576iPAlNCL5Zcp0Uw9KbzkTCubFz6OpWLHi+dQSkiSgdmgBVMrt5yTi3oBjPo3ufXKtT15S dHP+I/Zwg59wy1AqGSBBtxsHLtElCk6D6hf6HhKfigZagNDciN88laIkE7MUVwRPOb/IFzWTbc+ gVcfrkGu/UCiZpNp9EK+XyK2xygkwWB66RouKLGJHb9qd0pg6/rciP4MXbpZwTYbTFLbIyfPCje 949+erocdZJBnKEutPDCmgOjHJcdc= X-Received: by 2002:a05:6000:4308:b0:449:a07a:9676 with SMTP id ffacd0b85a97d-45eb38c1a3fmr36810708f8f.29.1779818205623; Tue, 26 May 2026 10:56:45 -0700 (PDT) X-Received: by 2002:a05:6000:4308:b0:449:a07a:9676 with SMTP id ffacd0b85a97d-45eb38c1a3fmr36810655f8f.29.1779818205137; Tue, 26 May 2026 10:56:45 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 09/19] scripts/qapi: reject empty enums Date: Tue, 26 May 2026 19:56:08 +0200 Message-ID: <20260526175618.227743-10-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818309689158500 Content-Type: text/plain; charset="utf-8" Raise an error if an enum has no members. Such enums cannot be populated w= ith a valid value. Do not extend the same limitation to enum whose members are all compiled out; they can still be used as optional members. Signed-off-by: Paolo Bonzini --- scripts/qapi/schema.py | 4 ++++ tests/qapi-schema/enum-empty.err | 2 ++ tests/qapi-schema/enum-empty.json | 2 ++ tests/qapi-schema/enum-empty.out | 0 tests/qapi-schema/qapi-schema-test.json | 3 --- tests/qapi-schema/qapi-schema-test.out | 1 - tests/qapi-schema/union-empty.err | 4 ++-- 7 files changed, 10 insertions(+), 6 deletions(-) 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 diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index 8d88b40de2e..78c2a25fc9a 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -428,6 +428,10 @@ def __init__( =20 def check(self, schema: QAPISchema) -> None: super().check(schema) + if not self.members: + raise QAPISemError( + self.info, + "enum '%s' must have at least one value" % self.name) seen: Dict[str, QAPISchemaMember] =3D {} for m in self.members: m.check_clash(self.info, seen) diff --git a/tests/qapi-schema/enum-empty.err b/tests/qapi-schema/enum-empt= y.err new file mode 100644 index 00000000000..6070bf62cbd --- /dev/null +++ b/tests/qapi-schema/enum-empty.err @@ -0,0 +1,2 @@ +enum-empty.json: In enum 'TestEmpty': +enum-empty.json:2: enum 'TestEmpty' must have at least one value diff --git a/tests/qapi-schema/enum-empty.json b/tests/qapi-schema/enum-emp= ty.json new file mode 100644 index 00000000000..3b3dfb2e3d8 --- /dev/null +++ b/tests/qapi-schema/enum-empty.json @@ -0,0 +1,2 @@ +# An enum must have at least one value +{ 'enum': 'TestEmpty', 'data': [] } diff --git a/tests/qapi-schema/enum-empty.out b/tests/qapi-schema/enum-empt= y.out new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qa= pi-schema-test.json index 8ca977c49d2..195f1c4847b 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -23,9 +23,6 @@ 'data': { 'enum1': 'EnumOne', # Intentional forward reference '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' }= } =20 -# An empty enum, although unusual, is currently acceptable -{ 'enum': 'MyEnum', 'data': [ ] } - # Likewise for an empty struct, including an empty base { 'struct': 'Empty1', 'data': { } } { 'struct': 'Empty2', 'base': 'Empty1', 'data': { } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qap= i-schema-test.out index 4617eb4e98a..ddd8bf80d66 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -18,7 +18,6 @@ object NestedEnumsOne member enum2: EnumOne optional=3DTrue member enum3: EnumOne optional=3DFalse member enum4: EnumOne optional=3DTrue -enum MyEnum object Empty1 object Empty2 base Empty1 diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-em= pty.err index d4284399621..c07dcf32a5a 100644 --- a/tests/qapi-schema/union-empty.err +++ b/tests/qapi-schema/union-empty.err @@ -1,2 +1,2 @@ -union-empty.json: In union 'Union': -union-empty.json:4: union has no branches +union-empty.json: In enum 'Empty': +union-empty.json:2: enum 'Empty' must have at least one value --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818318; cv=none; d=zohomail.com; s=zohoarc; b=HpVx6Kjfx4v4xTNsrY1KxyKxneX24fT4dGRT5xKtxtf/Bjvkqa4FRK5PH13ccpbf/DPPVMTSXPNrOVCmrAf0y7eSlfK8cFYZ4mBA+ybdtGTZACjmNA3B4JFM2DcJl192WtZ9hNz5nBkoh4R24OKdoikHSj3Bsz6Y0KpXWjZXEIk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818318; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=A5xgvznU+zEK4LsBHFLUJzRFiM54fPC5CxNWDMaKguw=; b=hSbrnrStWgZaMP2YSZM7ydHU+gUhDYo+g26/9cpcKJnW0CrCqwalPSiKAg0g0idgaA+IinUdGgWkG6VOAM6KRS/Oj3VysEVS7WWOrGBDmOCwdeZpCHDtocui0zMfIOOT3uOe0BJCqtafvM9JFlqWsGfMNE/oedlfqyfWwhgF5B4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818318331543.2589789972042; Tue, 26 May 2026 10:58:38 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1P-00025y-Ff; Tue, 26 May 2026 13:56:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1O-00025e-Aq for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:54 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1M-0007zD-HU for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:54 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-74-RGBrBxHLO3mEf705Eq4kzg-1; Tue, 26 May 2026 13:56:48 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-49047e9ca88so35851955e9.3 for ; Tue, 26 May 2026 10:56:48 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4904527f7f7sm509045595e9.7.2026.05.26.10.56.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818211; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=A5xgvznU+zEK4LsBHFLUJzRFiM54fPC5CxNWDMaKguw=; b=BeHmr/wZYjDuY4tLSk9WXuIsCtew99w4/XTaqgVlF+CNxMZWHlV0MbXujuVeyrtv6MLyq4 tSNAfzW3Orzw+sZZr1ryJw7Tz2cqCz2/ULd0HIMMBxpKD2my/Hx1vnYd12bVJ5i8NWpfwn 2iA9XTQlB5PCuZmjM5198ZukRNVZuak= X-MC-Unique: RGBrBxHLO3mEf705Eq4kzg-1 X-Mimecast-MFC-AGG-ID: RGBrBxHLO3mEf705Eq4kzg_1779818207 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818207; x=1780423007; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=A5xgvznU+zEK4LsBHFLUJzRFiM54fPC5CxNWDMaKguw=; b=lCgdnFc4KhlyHkdcMwwISKQYUNhiQkKT/wMLMKnYcAI9WFZUhZJzREFt+0OdcKSSLf AhLuLAJgQ3bFCec6HqO70+XRTkWO0c3/R/5sK+4zcucVlUbqIvyDqTyMur5ti1KVlDUH p0ScRuFIlBJMzSCzPr6L29pHshJ0P+hisDVdZ6XYwMKgOo/mddt8W/YcSK2w6Qv0MaJt ldZzMaipADR0CejN/1hDp+BQNKYPt0nbwanBPxw3C/zcd1WCzbr+1FpSVqKlc3y9ep8/ dKet/9AM/zQf8LnVAXQbvGvFl4L8WaHm1K2pz7YDmXDNXjGIhLBpmMW+RTRkfU2N8RMM 9XqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818207; x=1780423007; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=A5xgvznU+zEK4LsBHFLUJzRFiM54fPC5CxNWDMaKguw=; b=aZMZkmw+5dgPfyRNNZpQ0rDDeOxxGTdVahluv99uOYnE5tvmlV8DvFWZ9A6QqWGfV2 DO3h3Xop+M7DLiFHsoPrZLNO/y/BTWQKdTv5l+gWSHxbXSYVDkbkXjQvW/NpsUbpFH5a cRbqckH1HaaC7luzdsfw4NHb/LMcSvXjuRllnrZ0HflIrYYBmYz/LRgas1CKTvqHQXk6 nAJXkwsP5T4mMaTJ7NVRLv/+OlAWnRjjL+80gH0mB7v3rzdfWsGFogo+/IjGp1STs76m WwCSRQbVT6gtS+SmFu1SKH1VFOMeWt+7CGKFYY0vkbVt3ndXL0/dx89KB2FFCUDHLtWO pkzw== X-Gm-Message-State: AOJu0YyzqA/EH3JNxId1I8FpmofdbopuvV/sTxuP7l+qIZDHyFSaottB +ADLSNeDbpwep8V7bM21349aqLoW45gy0kVp4ICysYvEcPPf2Pgh9GL8siMxP0zbqM7IzxPz4Cf EIz9MreAMnTgXqzXU8hS3+Lw5uhZYM2TRtkCJIQDH+1kuNMk3lp4XXrMtoMM/jKWWo4IKwZTsYm DWQ2u5hsKUUhMmWZdkForrIbgXjbDNKt8vYBcAkqa4 X-Gm-Gg: Acq92OGswQme8J0sy2WeDZopa8n+i8ZIjqQzDSh/tq8O00TRqaYfwinldJtYOftE4+e aWlxoMj0rSpQwrtbgwostuLGBWxLkPAYnE9lAuBQEn904swr7EitSDJUo+Y7sL35OC32PD+Yjtg EhUM3ELnVSqmqnWse/Ei/C3R0kMo44Gv/T38Y/HO3WEznLWmd3iOdJ7JOpLHNI1NSLKEfOydqVA 5N+zlaQKezqNmnqYNxZwxIWY0QIKk4ityqHguhgyXzxZ9xXEhMWK1s9DvzbMWyHGwfdBbchBO9z 7GlMqSFTqmhWPaKDsP6Rj40kn9+Fuxq+DG8luwKFolUWznVu+dj0Qa8zHTA6CyNmTruIU9c3kdl aNRgowpp0FzwQbCGi39zzitDcuUzk403WQ3G2xhbB0iOG+c5o3Yk/TFu53ERr8PfTpynDucFDLx rPxJIC/kfW7IMuaV84oPgWcYFQm+d9mhcM0OTD/Q== X-Received: by 2002:a05:600c:4f82:b0:490:48e2:5618 with SMTP id 5b1f17b1804b1-49048e257admr293040855e9.22.1779818207046; Tue, 26 May 2026 10:56:47 -0700 (PDT) X-Received: by 2002:a05:600c:4f82:b0:490:48e2:5618 with SMTP id 5b1f17b1804b1-49048e257admr293040395e9.22.1779818206576; Tue, 26 May 2026 10:56:46 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 10/19] scripts/qapi: enum with conditional first item must be optional Date: Tue, 26 May 2026 19:56:09 +0200 Message-ID: <20260526175618.227743-11-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818319497154100 Content-Type: text/plain; charset="utf-8" Prevent an all-zero struct from having different meanings with different configurations or builds of QEMU. This needs some changes to doc-good.json, which used unwittingly such an enum. Signed-off-by: Paolo Bonzini --- scripts/qapi/schema.py | 8 ++++++++ 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-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 | 1 + 8 files changed, 35 insertions(+), 18 deletions(-) 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 diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index 78c2a25fc9a..a5a11298817 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -967,6 +967,14 @@ def check(self, schema: QAPISchema) -> None: assert self.defined_in self.type =3D schema.resolve_type(self._type_name, self.info, self.describe) + if (not self.optional + and isinstance(self.type, QAPISchemaEnumType) + and self.type.members[0].ifcond.is_present()): + raise QAPISemError( + self.info, + "enum type '%s' of %s has a conditional first value" + " and must be optional" + % (self.type.name, self.describe(self.info))) seen: Dict[str, QAPISchemaMember] =3D {} for f in self.features: f.check_clash(self.info, seen) diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.j= son index fac13425b72..76521ffe9e6 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -73,12 +73,12 @@ # @enum-feat: Also _one_ {and only} # @enum-member-feat: a member feature # -# @two is undocumented +# @zero is undocumented ## { 'enum': 'Enum', - 'data': [ { 'name': 'one', 'if': 'IFONE', - 'features': [ 'enum-member-feat' ] }, - 'two' ], + 'data': [ 'zero', + { 'name': 'one', 'if': 'IFONE', + 'features': [ 'enum-member-feat' ] } ], 'features': [ 'enum-feat' ], 'if': 'IFCOND' } =20 @@ -112,10 +112,10 @@ 'if': 'IFSTR' } } } =20 ## -# @Variant2: +# @Variant0: # ## -{ 'struct': 'Variant2', 'data': {} } +{ 'struct': 'Variant0', 'data': {} } =20 ## # @Object: @@ -128,8 +128,8 @@ 'base': 'Base', 'discriminator': 'base1', 'data': { 'one': 'Variant1', - 'two': { 'type': 'Variant2', - 'if': { 'any': ['IFONE', 'IFTWO'] } } } } + 'zero': { 'type': 'Variant0', + 'if': { 'any': ['IFONE', 'IFTWO'] } } } } =20 ## # @Alternate: diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 04a55072646..bf589061cbc 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -10,10 +10,10 @@ enum QType member qbool module doc-good.json enum Enum + member zero member one if IFONE feature enum-member-feat - member two if IFCOND feature enum-feat object Base @@ -24,12 +24,12 @@ object Variant1 if IFSTR feature member-feat feature variant1-feat -object Variant2 +object Variant0 object Object base Base tag base1 case one: Variant1 - case two: Variant2 + case zero: Variant0 if {'any': ['IFONE', 'IFTWO']} feature union-feat1 alternate Alternate @@ -110,14 +110,14 @@ doc symbol=3DEnum =20 arg=3Done The _one_ {and only}, description on the same line - arg=3Dtwo + arg=3Dzero =20 feature=3Denum-feat Also _one_ {and only} feature=3Denum-member-feat a member feature section=3DPlain -@two is undocumented +@zero is undocumented doc symbol=3DBase body=3D =20 @@ -137,7 +137,7 @@ Another paragraph a feature feature=3Dmember-feat a member feature -doc symbol=3DVariant2 +doc symbol=3DVariant0 body=3D =20 doc symbol=3DObject diff --git a/tests/qapi-schema/doc-good.txt b/tests/qapi-schema/doc-good.txt index 74b73681d32..922a61dcf23 100644 --- a/tests/qapi-schema/doc-good.txt +++ b/tests/qapi-schema/doc-good.txt @@ -43,14 +43,14 @@ Enum Enum Values: * **one** -- The _one_ {and only}, description on the same line =20 - * **two** -- Not documented + * **zero** -- Not documented =20 Features: * **enum-feat** -- Also _one_ {and only} =20 * **enum-member-feat** -- a member feature =20 - "two" is undocumented + "zero" is undocumented =20 Object Base *Availability*: "IFALL1 and IFALL2" @@ -75,7 +75,7 @@ Object Variant1 =20 * **member-feat** -- a member feature =20 -Object Variant2 +Object Variant0 =20 Object Object =20 @@ -84,7 +84,7 @@ Object Object =20 * When "base1" is "one": The members of "Variant1". =20 - * When "base1" is "two": The members of "Variant2". + * When "base1" is "zero": The members of "Variant0". =20 Features: * **union-feat1** -- a feature diff --git a/tests/qapi-schema/enum-if-first-required.err b/tests/qapi-sche= ma/enum-if-first-required.err new file mode 100644 index 00000000000..6d8bdcf2507 --- /dev/null +++ b/tests/qapi-schema/enum-if-first-required.err @@ -0,0 +1,2 @@ +enum-if-first-required.json: In struct 'TestStruct': +enum-if-first-required.json:5: enum type 'TestEnum' of member 'field' has = a conditional first value and must be optional diff --git a/tests/qapi-schema/enum-if-first-required.json b/tests/qapi-sch= ema/enum-if-first-required.json new file mode 100644 index 00000000000..1769b5fdef9 --- /dev/null +++ b/tests/qapi-schema/enum-if-first-required.json @@ -0,0 +1,6 @@ +# Enum with conditional first value cannot be used in required fields +{ 'enum': 'TestEnum', + 'data': [ { 'name': 'member1', 'if': 'CONFIG_FOO' }, + 'member2' ] } +{ 'struct': 'TestStruct', + 'data': { 'field': 'TestEnum' } } diff --git a/tests/qapi-schema/enum-if-first-required.out b/tests/qapi-sche= ma/enum-if-first-required.out new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index debff633ac1..3b0c16a8b67 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -97,6 +97,7 @@ schemas =3D [ 'enum-bad-prefix.json', 'enum-clash-member.json', 'enum-dict-member-unknown.json', + 'enum-if-first-required.json', 'enum-if-invalid.json', 'enum-int-member.json', 'enum-member-case.json', --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818362; cv=none; d=zohomail.com; s=zohoarc; b=gXygZoM+Lg7U8MlDJbAD14pIrypE4m+k72F4VNEZr13tur6Io/GOUMFOmaiKUNo8Db2WF+dxlozx7+LeDDAMyFKrT7pQs46LLMn9yJT/rPQ6tlyQXaFtM0jle4s4xzmJm/7UOGox5fpdSm7bSPyqDUEbZGX3zHv+auFpCS3hGXI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818362; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=8gANO1dHY/McFEVD+OLbOHVJl89l7bOu5SWe3UKWw+s=; b=gDOV5Fxeic+0sG9ZW5yVwmgjVljKSNydtZsz7c1QG0iKcKfen40PZGtsJZyRcaFPoV13OZ6+enPIFFqxb7iU+4E3MaIupO9CsIE8Ql//EuWcB+u5P24+/wMmpGeWd3MkuRVjXrOdW2e2MIgcsPKrypTT7FMywhs2wCVzg8xBA+A= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818362534373.91003022147663; Tue, 26 May 2026 10:59:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1U-00027f-Lk; Tue, 26 May 2026 13:57:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1S-00026S-JV for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:58 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1Q-0007zp-G5 for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:58 -0400 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-343-o8Dxr3FuMGGs9xxV9w2g7A-1; Tue, 26 May 2026 13:56:53 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-48fed2519daso50325825e9.0 for ; Tue, 26 May 2026 10:56:52 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490454a0b9asm336803755e9.11.2026.05.26.10.56.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818215; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8gANO1dHY/McFEVD+OLbOHVJl89l7bOu5SWe3UKWw+s=; b=e8JNOSc3xLizmHbBb/kleWYeIskD/UoNEFIjEFXWzSfsiIGIErT7IRxHbkUyxDd1BoEEYP bBpNnuTqOdoZ9tVYeesBO3bUD4H/KJMx++nnV1WJZ7LAv3e3ZqETvNQdQTPomVR1tfwzEd pDTxX/SlZpIT9YZ++6cxEQ4YU2k4UI8= X-MC-Unique: o8Dxr3FuMGGs9xxV9w2g7A-1 X-Mimecast-MFC-AGG-ID: o8Dxr3FuMGGs9xxV9w2g7A_1779818212 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818212; x=1780423012; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8gANO1dHY/McFEVD+OLbOHVJl89l7bOu5SWe3UKWw+s=; b=nL+j+3yqldfVveJyP85QQrG+/164sLvD4q62M4zqjG4xA0UjySK7EHJalcWkbGRr3R l7R6H0qb4zqTk8AJMHGu2yPEUYgfQxdYlFupaF/y4kWVcZovxOAuYDh1O04OxNpifD1s 4YO+q5+YkyuStM/d2s5DtdcBQyCe8pAyjsG9J+fa0xDmEWJao0E1yQPVi3rRCBzk2wET 7rhLVjN/lKLowfdovzYA0cu5UrAF27DdhuAYoqu31RgVEk5M7ysm5w5XdOhtR8ZVC+Cc u4SSUJEdbPuYRYFlwfu8HwkMc/Tf0LyKiA+Byn4ukNudvPcbhPJVdDtEoQQYldKZVJdv gauw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818212; x=1780423012; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8gANO1dHY/McFEVD+OLbOHVJl89l7bOu5SWe3UKWw+s=; b=oNjAWMx3L+ryZAMzD1U/pC4PSt+4X3vvdga1gUABKCjI9jkQR2KhDyZCW2AAJo3GP8 ulWRIUcf6eUy+poZwHviHXs5ihQQxX57KW3SH3Og0c+LvJE7JulGqpjRv/QILDlS6tgi fXAwxA75LqM6GZTN2Sw0OlWTqzH0h9ppSsqG4RkE67ETDnEn5YmkGpG7jHn3ahyBGDmU dXLp5+YwmjeIxib+Te21pWKGR7+/GJtD/C7cyryOSlBuqYdopqxlpdOFG8ZhX/h8hCnL +DrGu3jGAmjO5jpOE08ma2IHaaJd9GsEtiBVekDwmuJax6qygDA83j2aciRwR3mzqGn7 V2dw== X-Gm-Message-State: AOJu0YyES6uwH2DxdakZb1bNe3Oyy9hbE7mwP8x5+/q68db7eDQ3+P2M FuPTgcHcLhNTrL35LEFotlPDktQ9dFT7ozuYGt71uB7Ga6mu9HMZNHOtFoxny4hrFCNwTn88Q1o CCFusddl3Cx2DV8Bx8C+GUb4y1HTKntv0723EBaCG2/KIhCkECY92wRl4b6bjD3oj8CrR8A255I qUJfquP1CyjGQl/wbLiQV965Bz9z9iaX/Cy3g8aEo5 X-Gm-Gg: Acq92OF0rwwdPmy2pN2SmPxKnU8hbD/LWbKAU96fVUZVZuo2CmzSdADiIJuG4HYvj+l ke+p3sYkMU01vVn6D876pjYZBsbijtqqwhN/YRhXIgEqZ4BiFdejrD0XLW8Zps2Knjce+SnVD8w ENfLs5gdOTCf+zl0Ae/W9SXbbrZ5EIVGF9bnH/4bMLO+VuslHANsSMadWnYZyEFU9OjdbNVZDXP OtJJij9nQ1brdDknUiQVARTqxI8VcAXqaU+T/O0w7MxYBh8Up2GlWiTGJlKcN2YTSGlv9JBNkHu U5JUIp7CfOhyvDL74dSqKhOEUhcoOXXZ4YrI81b7f1RFyNUt5VK56iiRssjN4nd8onCESPKAigv rjImXHZKs+vR1E/zBuj1/BBUHxjmoinXeZzR14TVSV2UyfvlpxStYsElHn2ZCJ+uP2sZvVESd3J liEM1CP69hNrdDUE9CUojy0rY7/x29LpefmCydXw== X-Received: by 2002:a05:600d:6451:10b0:48a:563c:c8c0 with SMTP id 5b1f17b1804b1-4904249d11amr239850625e9.7.1779818211988; Tue, 26 May 2026 10:56:51 -0700 (PDT) X-Received: by 2002:a05:600d:6451:10b0:48a:563c:c8c0 with SMTP id 5b1f17b1804b1-4904249d11amr239850315e9.7.1779818211595; Tue, 26 May 2026 10:56:51 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 11/19] scripts/qapi: add QAPISchemaIfCond.rsgen() Date: Tue, 26 May 2026 19:56:10 +0200 Message-ID: <20260526175618.227743-12-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818364066154100 From: Marc-Andr=C3=A9 Lureau Generate Rust #[cfg(...)] guards from QAPI 'if' conditions; it turns out that they are very similar, with both of them using not/any/all, so just walk the tree. The next commit will put it to use. Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20210907121943.3498701-15-marcandre.lureau@= redhat.com Signed-off-by: Paolo Bonzini --- scripts/qapi/common.py | 19 +++++++++++++++++++ scripts/qapi/schema.py | 4 ++++ tests/qapi-schema/meson.build | 1 + 3 files changed, 24 insertions(+) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index d7c8aa3365c..14d5dd259c4 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -199,6 +199,25 @@ def guardend(name: str) -> str: name=3Dc_fname(name).upper()) =20 =20 +def rsgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str: + + def cfg(ifcond: Union[str, Dict[str, Any]]) -> str: + if isinstance(ifcond, str): + return ifcond + assert isinstance(ifcond, dict) and len(ifcond) =3D=3D 1 + if 'not' in ifcond: + oper =3D 'not' + arg =3D cfg(ifcond['not']) + else: + oper, operands =3D next(iter(ifcond.items())) + arg =3D ', '.join([cfg(c) for c in operands]) + return f'{oper}({arg})' + + if not ifcond: + return '' + return '#[cfg(%s)]' % cfg(ifcond) + + def gen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]], cond_fmt: str, not_fmt: str, all_operator: str, any_operator: str) -> str: diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index a5a11298817..7bb9fb712cf 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -37,6 +37,7 @@ docgen_ifcond, gen_endif, gen_if, + rsgen_ifcond, ) from .error import QAPIError, QAPISemError, QAPISourceError from .expr import check_exprs @@ -63,6 +64,9 @@ def gen_endif(self) -> str: def docgen(self) -> str: return docgen_ifcond(self.ifcond) =20 + def rsgen(self) -> str: + return rsgen_ifcond(self.ifcond) + def is_present(self) -> bool: return bool(self.ifcond) =20 diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index 3b0c16a8b67..40429a22774 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -97,6 +97,7 @@ schemas =3D [ 'enum-bad-prefix.json', 'enum-clash-member.json', 'enum-dict-member-unknown.json', + 'enum-empty.json', 'enum-if-first-required.json', 'enum-if-invalid.json', 'enum-int-member.json', --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818361; cv=none; d=zohomail.com; s=zohoarc; b=TxDAD0AqJ2AkXcQdIomgEDtL6fPHeUfHpbvObHG2focFVB5KKyqbU6AMm4bLTiaoL+3WJQ5iQcoMeQ+jGV5YkSqy1Ej7MObm15Rn1nRqtRn5jDGFAssDvIM8UTOOaUcw9Kj/m5zBTnTvv+zcnudqCT7T0Ffuh1XwJMjMEUA2riQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818361; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=x3lLT2zM00XZeVcrpc+cb0TqWQYGfu4gptrjRd0nz6o=; b=SZTjjfLPNi63lXhktVCv/GfeejJUF3A7Gej8LeGrWLUvuT9geILHC+uAzkh8nbhhvqUAXM5dhESEzKfRviCYLQrM1Pr96bzqcC+3POnpE/j/mv2ViiOJ1L7O38cy22x0RdmJ+s0PLC/n1qnvkANT0PBUKStuZvetdb/3e3tI5fw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177981836119994.69099282626087; Tue, 26 May 2026 10:59:21 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1U-00027j-W6; Tue, 26 May 2026 13:57:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1T-000271-ND for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:59 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1R-000808-QK for qemu-devel@nongnu.org; Tue, 26 May 2026 13:56:59 -0400 Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-634-_zrekPNZOkyZp2a0qkpihg-1; Tue, 26 May 2026 13:56:54 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-48fd3dbd16aso89637915e9.0 for ; Tue, 26 May 2026 10:56:54 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490454a0b9asm336811565e9.11.2026.05.26.10.56.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818216; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=x3lLT2zM00XZeVcrpc+cb0TqWQYGfu4gptrjRd0nz6o=; b=FAo7on2NHMzgNfweteSeKda6zihxGv2TXACUkoR20dTfyzhYo00wMEZNAIdJ63Oa8t8rSS nAilVg1elkmfFb8MaCJaRs2wv8TmbrzxpqYprChzkLpbwhjphWG9ElqFDWM3fW6Zgd6mUT yDPpqoktKXl51/WkxyFfxbCRotak7ks= X-MC-Unique: _zrekPNZOkyZp2a0qkpihg-1 X-Mimecast-MFC-AGG-ID: _zrekPNZOkyZp2a0qkpihg_1779818213 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818213; x=1780423013; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=x3lLT2zM00XZeVcrpc+cb0TqWQYGfu4gptrjRd0nz6o=; b=bCjlcBJmyS7EVMEQ7yJ5R774x/VHZ0C6aPfWG5sDIGVvPqvO6mbgtaBQFap1UAE2Iu 2nLqDI1lTcJHebvd0IUOot43hXCjSJ+zgrmHIdZneUggG3qDWS3gdCybZ8n0GyFHX+am ervW/LJ1O6UiYWhloRyQsOWWf+lah07jseXv8EugTSdmabg5iDQFOukhYDmXmzro9xBH gOvIWlMPHNVwS98VZ0VK/c38N5f4JkNViY8Pnybj2QsOkgw16J7Okz25B2CuJ8kv/sGJ CZAcUZYHCfrV/SW5pvtnAxOaLjCYlqoq67KhhFCGySo9kFIeAUi2poCiDKIZfrDA7zI0 fYkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818213; x=1780423013; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=x3lLT2zM00XZeVcrpc+cb0TqWQYGfu4gptrjRd0nz6o=; b=oDDl5ENQiNANNm/gm/4ElSUdBtjqpSr0nSQdm3T7B3YU3nlW2ABIMMxyqFD16q10pi krmwwMtw3ZLspLX55YXp/DTT8UQwG6bbm+pyAP4JYJtIEQqtKO0YKZqWFAuUO0aHXmxT v7iKYnINACxFk9LEXwUHyUmzh+OrIBsscENK/UpN1sbWVugTKuLlM902QoY2e7uMxVfS ngbTRqJdmzpra85v7LCwrpbkiBWdKowDhoecl7nqFU6qAcXHLBbbmAnoQ6ibVWE739DP SLiR+MgakoPrmktr23NfNT+Df8JWurGs01ahF120+x2BBcQbiN+tF7eSu7WDUZD3xUNl aFHg== X-Gm-Message-State: AOJu0YxqMYCBQ1Db4+4kRUnxQMTvyctpOfyZ9P9Lqqa/yVvxHgKjR5wd ZjS1fInl7HBEziex2bhKkerz7+J0LWy8QSIwaMZCP8QOrwz+D1VzaWuu+/NsbvWxyBNm8edDNh5 L54t5st3I5nDaYg6i0H4kTwaHN9FLTFim5RpDNh3QJnq1wCHCSHWLsQ+whlfFcHO59FS+4NqZUl 6iZaxrGshm8n6UQ0C6VHavfIWciVstsA27JSnWdYvK X-Gm-Gg: Acq92OF1kGu5waqusLgfmLgx2HoimpAuKx5/uyj+nglMiQLlKWy2Wc3Pm0jegcJrX2m HW5HgH7DdKalip4R+PBgtTwWYIkB5qRJLjceHIb+j177Da3cA8fvDEn4IOGMiFnyy7E/laZqEVF FnSyvbptbTU2LEJxeU0bAdoEu/Xxf4axlC8hD6bIQtq1d94HGAZk1rMqOGJdLjQCpkN3oTu8DBR Qln6ZGbej+KVdZtDuihdrpL8S3XUFQYipIM0peokRwvKSNES+Rzfjd5sKzU0/L82yPeh+m3o+1I pumdZifgNwFg6MFd973WOGIQOr+1iB3D3hx1mewVh4WgUfO6hYsTy5oc9W7Tu8vnzwIXJsu4tTL /MJc+FxUlwp9y3vkGSw7fCTeztmPkk67O0M2mKALu5pH+ckjYJ3qp6mmmgTAiByhdBMQENT8qAL p2iTwe9W1hQqv8u61+HBomxKD+ats= X-Received: by 2002:a05:600c:8484:b0:490:3b87:be0e with SMTP id 5b1f17b1804b1-490428e3362mr339037765e9.29.1779818213280; Tue, 26 May 2026 10:56:53 -0700 (PDT) X-Received: by 2002:a05:600c:8484:b0:490:3b87:be0e with SMTP id 5b1f17b1804b1-490428e3362mr339037425e9.29.1779818212907; Tue, 26 May 2026 10:56:52 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 12/19] scripts/qapi: add QAPISchemaType.is_predefined Date: Tue, 26 May 2026 19:56:11 +0200 Message-ID: <20260526175618.227743-13-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818361868158500 Content-Type: text/plain; charset="utf-8" It is impossible to call is_implicit on an enum type from the visitor, beca= use the QAPISchemaEnumType has already been exploded into its constituent field= s. The Rust backend is also not modular (yet?) so it is not possible to filter out the builtin module; add a way to query for implicit type names without having the object itself. Signed-off-by: Paolo Bonzini --- scripts/qapi/schema.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index 7bb9fb712cf..3459b8038e5 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -1255,6 +1255,17 @@ def _def_builtin_type( # schema. self._make_array_type(name, None) =20 + def is_predefined(self, name: str) -> bool: + # See QAPISchema._def_predefineds() + entity =3D self._entity_dict[name] + if isinstance(entity, QAPISchemaBuiltinType): + return True + if entity is self.the_empty_object_type: + return True + if name =3D=3D 'QType': + return True + return False + def _def_predefineds(self) -> None: for t in [('str', 'string', 'char' + POINTER_SUFFIX), ('number', 'number', 'double'), --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818304; cv=none; d=zohomail.com; s=zohoarc; b=BU4VPmag58Ejv0JHTvKivDG9k6FoEykAM0AKZomgrjA8iFcnX4eb2DEvVJNhVBwOC12mSFts5l305cV0MtMKg0xfeFHsopvFEWzAZwVb2jvHlgSTLRyBF2nFZ8Vcb6wb6wkq0YB6AjNlhqbyshBRf+EPV/veHRfOn86sbQsAapU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818304; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=rwl60sYUdvU2FK56rokuqANsEss1jT96qzp7KeUwX2U=; b=YNKgpRj+0jJg56MEoRSV/OYYJmnHcGs7pkEYJD9BGldf3nS08xUV1B11D/D2Bhu4zWShov94Hli/vBsuoKqG+18ottsO+gw/GxJh8E7kY4lpYsPMZm2BVSUAOU5vkwGEr9pWB2f9Jas+IhQM7U01Oh9PK+5CR9cdlg7cyvjjIWk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818304301741.8329182199282; Tue, 26 May 2026 10:58:24 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1a-000292-Fd; Tue, 26 May 2026 13:57:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1X-00028V-Ql for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:03 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1W-00083A-6r for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:03 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-336-jtg3TwA6N263jH-W2eCZBw-1; Tue, 26 May 2026 13:57:00 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-49050c44bcdso44482695e9.3 for ; Tue, 26 May 2026 10:56:59 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490452765f5sm354517775e9.5.2026.05.26.10.56.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818221; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rwl60sYUdvU2FK56rokuqANsEss1jT96qzp7KeUwX2U=; b=CRbzEtu9kOFKPK4EmYDWvkjyfEKMVQB3CVPJr0ZaqBmOh6j4UFdO6zz1f3p70onFsGeoZp 42Gd3kaW4gPwkKy4pbYCGy4iZtUZJNmZs42sPuTVvOruC0SQCGytCEAz9asMqhFuuw4H9o prNkSTDt3NjQTBykXzpbfwDUHUvu3P4= X-MC-Unique: jtg3TwA6N263jH-W2eCZBw-1 X-Mimecast-MFC-AGG-ID: jtg3TwA6N263jH-W2eCZBw_1779818219 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818219; x=1780423019; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rwl60sYUdvU2FK56rokuqANsEss1jT96qzp7KeUwX2U=; b=uE8dy8waR+6vwt4OTqdZd9aEgSY7n3PZ+jDmG6ViQpqjJfPsO1xPK9S+OQjkZf3KnE X4TwXHnJW+3lYxM+FV2PHrJJkY+FYjV2/eF8W91BUtVB98xlLzHxMXBrVTlEu89jDmZO 56yg0mHsb9pDku599Ga2VvQ2WWNbuPkGP6DgRe31gFXjp7rliL9eJzPbU5f1nJEgHqy0 vztmfYMRitwvFYyzd3i+lNJkDYX0GqGXDKPk3IO1PV9Oo+t7p4aXRIfF14eJE2nVuopJ 00MDwfmL9H43QwoOznYxUZt7ZVt7jZ9a7b3LCHYHEEMMCmMdxF7blg9jljgnyu/se/Fj kr7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818219; x=1780423019; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=rwl60sYUdvU2FK56rokuqANsEss1jT96qzp7KeUwX2U=; b=XGryVIU0nxsJLevoHHjz8hdxe+Uly1OtIFsJr8Tu7peH/2ifsPX8ZVCVDQyHC30NzH Xuy1fD8EWMKo8OnC8oWbRIDOzVf9y/IkRleCkHBg1ialP11FPKhzcN0wo1mwznE/Hfr1 GqhXlq09z6liiPxqPmFD7DPqRfGIktxa6kFO6ghSA+RmDVTOw0evbXRM62Sh/IXPAWFD Xl6fPKqTUG2qHGOoP11ELGe5vYiEe6iS2Gg7SVZ7LZ52YPbawsEG5/pYzk1507AKPpQj cml82nddagzndziAHIiDeFhSpu1W9CFSihzxIEtRM6OvNb/prH9518vfkONDKXdmhr53 G9cQ== X-Gm-Message-State: AOJu0YxaZJOqSzYFED68xCzZVl+OXQlOMEkcnIQ2LpL4KeY5g7EcoD4O B7aZSzwqgP/NW+rjPKhWCm5qubZFGt8+8oWkmPOwCpBVNyQzVQDi8UP/alqkjtwtOt22B7kv2t/ 52qqcFZ8GFQU3weXaL4TxHUg08dvInOJ3jz/Vgxx1GoXxNkwWB6RMMLQVlIQvluWzn5nfLJTtps DBI0ZV5cClphAehg7P3JbGuLe1MhOVDExH6hwk5CaG X-Gm-Gg: Acq92OGUefDqImnjf+nlPK1/1yyxFWSelcVOTgwvelsp5YNIjWMe43InTJBGcXahp15 gpH+hXtQ6HYSbOnve5PYqLClIMlzwNVDgJECJluIupP/+cF8rdoH6AoOru9rK8xbeQ624dKwvax j/mxNOXkgQx8NVF9dmOZeOUOKlr1+4qoOGFS1Kou0APTLWzO4oeaLSUp3DTjRFmqVahdFMoFC7W /C2UMvkmocY1dQFH9e91jhIz8jckd4yqeQu/P/ya1zlVdUaK1mAsoH1ihvFsgRcSkr4SZGdOxpl pBIPOBWkmoeCB7azEhIROTAb52Hrnt45ElQIOxDX3U7fkxXwLTVCdsGunpdKlBdQr4I2q8k3YlU Kfec3MH87sRgunMRAdbBqFmOCv77Z57FDz1EVSAWqMmVCNgdM1LBx9XfbyZCoTlthocMSYin+Qe GXQmFQ5paYeaVUisjNEx/RChSyrcw= X-Received: by 2002:a05:600c:818e:b0:490:58f4:ba23 with SMTP id 5b1f17b1804b1-4905c60ef29mr193631825e9.30.1779818218768; Tue, 26 May 2026 10:56:58 -0700 (PDT) X-Received: by 2002:a05:600c:818e:b0:490:58f4:ba23 with SMTP id 5b1f17b1804b1-4905c60ef29mr193631435e9.30.1779818218325; Tue, 26 May 2026 10:56:58 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 13/19] scripts/qapi: pull c_name and lstrip from camel_to_upper to caller Date: Tue, 26 May 2026 19:56:12 +0200 Message-ID: <20260526175618.227743-14-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818307248154100 Content-Type: text/plain; charset="utf-8" Allow using camel_to_upper for other languages too. In particular, the lstrip() is needed to avoid reserved C identifiers, for example: typedef enum __org_qemu_x_Enum { __ORG_QEMU_X_ENUM___ORG_QEMU_X_VALUE, __ORG_QEMU_X_ENUM__MAX, } __org_qemu_x_Enum; Insulate Rust from this, since underscores have a different meaning in Rust (though only for the sake of warnings). Signed-off-by: Paolo Bonzini --- scripts/qapi/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 14d5dd259c4..c75396a01b5 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -61,7 +61,7 @@ def camel_to_upper(value: str) -> str: ret +=3D ch upc =3D ch.isupper() =20 - return c_name(ret.upper()).lstrip('_') + return ret.upper() =20 =20 def c_enum_const(type_name: str, @@ -75,7 +75,7 @@ def c_enum_const(type_name: str, :param prefix: Optional, prefix that overrides the type_name. """ if prefix is None: - prefix =3D camel_to_upper(type_name) + prefix =3D c_name(camel_to_upper(type_name)).lstrip('_') return prefix + '_' + c_name(const_name, False).upper() =20 =20 --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818449; cv=none; d=zohomail.com; s=zohoarc; b=Ux/9haG+oDzchXz3FQoNYHl1dIHCxIF1FcxVZQCrHPgxY2UWjdfxmZlbXCbeZW34lszWos9heLDlegRMOPyv0HjLsqg94n5oaTYkuTiUYZ9tYc71dw4wyIyDuH5laotF3TgV2lKFWbl478Omx4Miu+FUy2DTGO6C8ou29d4rk2c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818449; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=xeAc90a5JobVPESwPbooIYpcQ6eg5eVi/LK44TKf77M=; b=FRHm2jGLTPsunI/EMgy1U9fuLr3aKJdXagrMCgTS7aYljlCdBix/zNkOfk5euekESY8SHIhGQ8/YURq3Jjte84ZN0s939qyAZWvvy9hwHO4UkWE0B7noBdlnsEenCNqu00eWWwPLuTYndfDRai1XC3ggDc9ntbdK9WiMPrYA/Fo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818449347434.4608215708337; Tue, 26 May 2026 11:00:49 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1e-0002A6-Ho; Tue, 26 May 2026 13:57:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1Z-00028r-1w for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:06 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1X-00084a-8f for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:04 -0400 Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-400-o3vQ8yzLOtWEuWNoyxSzLA-1; Tue, 26 May 2026 13:57:01 -0400 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-45ea19f2564so5598847f8f.2 for ; Tue, 26 May 2026 10:57:00 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6d4ca0dsm37040170f8f.18.2026.05.26.10.56.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:56:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818222; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xeAc90a5JobVPESwPbooIYpcQ6eg5eVi/LK44TKf77M=; b=W8TsWQZYnW/N3zQlgCu5u2wVTiaBOVfy6H+MaHNKC1Eg/SbhMZ1V6hrtzLQ4ibYmEoKSA6 28RxZrQe5vSWjHd3Vg/QgSIr/KAjUt+bYUrYkcB0KVdZBeKVY6zGBR4bj/qpGWEUKYAQqm bXX1PgBkkHY3Sm2U7o/XLGKO42C9Bac= X-MC-Unique: o3vQ8yzLOtWEuWNoyxSzLA-1 X-Mimecast-MFC-AGG-ID: o3vQ8yzLOtWEuWNoyxSzLA_1779818220 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818220; x=1780423020; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=xeAc90a5JobVPESwPbooIYpcQ6eg5eVi/LK44TKf77M=; b=WqsUk4e/aywkSRSUBU2XRg1pOmzEsR7HZqkooA0T1js3pFjYc+7bxGV5ujNgwXkBL+ 4aPDjfZAcSRym2uRNEVvNvgRli+ex25nAejMz0I/gikWYUb7ZulYlubH7enRXxEeA4+R te3T57I9ZlmGQD8WwAQcCecm8n3Dbum1BeZiog+greh0diw6J3+emi0AzfO0csnWsfbe PgJuETRQernUijCAS0ZJO4sLvDirWLJP78Dp//FCPyta+jskur/YgwacQgFxMoIwDqB5 nF2aqoxafAxuAAUqDb3wiYSA5OS9b3fprC/nBrYydpXhKbrJckfHLSzFwKYxM+YfU7iR RKLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818220; x=1780423020; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=xeAc90a5JobVPESwPbooIYpcQ6eg5eVi/LK44TKf77M=; b=aqDlvwCrU2EVB8MoB/hciKtcTjdyn2YKUKiUxOz4zz/ltIx5J0ykwyrYYe7dPE0QTk cZrxQNi5kJqLDZtJRQpkQR8rNYXlvCYglSbFmm8eH5VGyRoXpZ52eCHzRSohegGMKr93 sR3M9+xeeCePqbq4vZLXqL1bt+W7t6TmNG0JNjZOVI0Snn2eIiX5Z8qOnz0VdoHwp4bi 6NFjQqqZqxw/X/zreqOQLvgHGMfZYe5yRPBsoLfcccPJJp3e9mG5RKNuWhUE+7RXCsBd CNGQ7XZJv05L4o+rAEQCMY0qpvaOjqZxH9lZnPnUWo6ckYsBmc/HI1XCk0uYU2vA8zgZ tPJg== X-Gm-Message-State: AOJu0YxRm3DlsN/9Q3NCsPgwOKUcbtaEANjr1pF9QYYsRme9+JHoq8Ju LRifEYPsfJdwIsbyyDFPI1KjO1CMusXwHhNW+Xg2fiz3mQLLAglzRTkMZxuHzpWIZsCkvikG4dW sZyQISqr7NSzI6FCTx9NGDOQubdn6e0ZEY8CQnbrDS6IZUxngMkCrgdxzwyX96UIS2rzG+GyCdA FuXppbtWxom4yRIKpIonfuDD4D2o3oul8gCpUB19LS X-Gm-Gg: Acq92OHLPpoMzn3gmkAzFiWhRteuTSI8ynYSqpfe0BDLY6+yJglL7RqT3FKYsAwylKM QrWdz+0vV1wZtLN70o/1+2jpvbTGQdm7kw6KZFpfYtmUYNsiitX+C9rjVHdLNYcT9VyATIWceHe SqZt5aEPr3fkyYD8m8ebs/FPaNmwBKXdl3SvwtUd5MOEpwF3c9MBU7/KOtk5+7cjaLcdcifrVg3 nj8zpLkIfy8hbFBoRigyctW79QGIFBoMaCmWLiOy+iLZYmp1J5HLCQ//B080bPs6/8cqQPUhWMd tPm1dsAqxkIqH2FGIydsvlQE4JFIcrwTr7wqc85gbCyn2U3qgdXcVpIXfYsqMinRdW7SpbcEsE2 a9G+2Ryfkkg2UZi1f6lk73iEuHtIyI3MTDu/s8eeIN+kOMZF8N3bO8gK0fFIcUHbuJRaLMt8IoP 9LZTN/mbyXK0I9urpoCf3XEvXnExY= X-Received: by 2002:a05:600c:1c0d:b0:48f:d612:3c59 with SMTP id 5b1f17b1804b1-490424b3927mr364696685e9.9.1779818220026; Tue, 26 May 2026 10:57:00 -0700 (PDT) X-Received: by 2002:a05:600c:1c0d:b0:48f:d612:3c59 with SMTP id 5b1f17b1804b1-490424b3927mr364696345e9.9.1779818219652; Tue, 26 May 2026 10:56:59 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 14/19] scripts/qapi: allow passing multiple segments to mcgen Date: Tue, 26 May 2026 19:56:13 +0200 Message-ID: <20260526175618.227743-15-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818450800158500 Content-Type: text/plain; charset="utf-8" Make mcgen more flexible to allow for easier removal of empty lines. For example, in Rust you can have #[cfg(X)] lines that would often be empty; let mcgen remove the whole segment or at least the empty spaces and lines at the end of it. Separate invocations of mcgen still preserve the empty lines between them. Signed-off-by: Paolo Bonzini --- scripts/qapi/common.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index c75396a01b5..44229c2e366 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -172,10 +172,24 @@ def cgen(code: str, **kwds: object) -> str: return re.sub(re.escape(EATSPACE) + r' *', '', raw) =20 =20 -def mcgen(code: str, **kwds: object) -> str: - if code[0] =3D=3D '\n': - code =3D code[1:] - return cgen(code, **kwds) +def mcgen(*code: str, **kwds: object) -> str: + ''' + Generate ``code`` with ``kwds`` interpolated. Separate + positional arguments represent separate segments that could + expand to empty strings; empty segments are omitted and no + blank lines are introduced at their boundaries. + ''' + last =3D len(code) - 1 + result =3D [] + for i, s in enumerate(code): + if s.startswith('\n'): + s =3D s[1:] + if i !=3D last: + s =3D s.rstrip() + s =3D cgen(s, **kwds) + if s: + result.append(s) + return '\n'.join(result) =20 =20 def c_fname(filename: str) -> str: --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818360; cv=none; d=zohomail.com; s=zohoarc; b=Q3BiGEL2Jt3k3uXwhu+m9El924GdgMmLIXYuvfuHehCca/trmWJnW/7Rfs6Ko4pWLlVCfJRewSmRX4zax2Vq7NMRWsjohsPMfy8+sBb/2zBTjxnGLNWR0u8LigkTDYE4EmAmEXENhjUfpAfCFRSC/1JWpnfalRyGzb+woeLBG5U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818360; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=aGWu35VmQEneAMBA3a8cwbjLC3K3U1BtEBauRdrmvuA=; b=OtknxfLHIEDaaSK2N1u/dpnsjeZY9g/KbIDj+mvD1z8N6OnyXmGEdKyBY1RM+h513JOC7q0Ez7vYWrvS7ooAyI89xmd58aJTaAdtGY/1ErdBB+MUbT3wyzUQ5MVWv/7oO+Da3CrhzUlNZDwcJ7RUyDXOWSwwHnA8hejPCAVl/28= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818360253922.9106869065031; Tue, 26 May 2026 10:59:20 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1k-0002IZ-2V; Tue, 26 May 2026 13:57:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1f-0002Aj-7a for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:12 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1c-00085E-0s for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:10 -0400 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-66-pCe8Vu8XNx-RGv-uHgz4iw-1; Tue, 26 May 2026 13:57:05 -0400 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-49047e22ed4so35591435e9.1 for ; Tue, 26 May 2026 10:57:05 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490454a0cd5sm421279595e9.10.2026.05.26.10.57.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:57:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818227; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aGWu35VmQEneAMBA3a8cwbjLC3K3U1BtEBauRdrmvuA=; b=bH3dQuKhv38pLM+KHLS9zkJiilMaPEB5PLJ+byGUBZs7ocNUIT8saelaFKryakMmDasDJC y3ILuYLB3YF92tUzx5TybLIHRwSdrmnsXB7wuAfJngVq84KRZChXkvzZozCT+8A+I43eBK hNyxl0C+vDTlzjuNuS7bi5w7dan/dfw= X-MC-Unique: pCe8Vu8XNx-RGv-uHgz4iw-1 X-Mimecast-MFC-AGG-ID: pCe8Vu8XNx-RGv-uHgz4iw_1779818224 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818224; x=1780423024; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=aGWu35VmQEneAMBA3a8cwbjLC3K3U1BtEBauRdrmvuA=; b=HwwvVhqh7lG08LhiElyHEsEy636AgGB6dxtl2AmzQVarkUlyafh4RzSP2NtPp3pb6/ kfpbqlmztUzIhvfJy4wwWWoED7nx0yynLpxRg75shKT4NwrBPQrORrcjXzatH/oKFLIf QGiCUBwaugrX9FvbZkWV0iHMVmBJe+RdGwBSUL11BnvSjXGUPaCuIrwSDDSheBMvYveV K/PZ88C8dO5opSgUvszw+ktdMeZi+uE6QpgIWn06hiiXW7FS7ctx7LI1/t4mm7LWdoir PZ6OYZ4uP7MIFmXlMuupMbeifydg2oQV1hpNbM82NaSQq3W+VRTxrvLBvorJ/mRu2Bfn 8b6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818224; x=1780423024; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=aGWu35VmQEneAMBA3a8cwbjLC3K3U1BtEBauRdrmvuA=; b=dYp/WzKGB4QkvbhdLlEK3d43+5f0I0XSt15jDXEEFI1T3WmLiggov+muU8zRpgZEsK d9ebTr0xM/BvEZJJtqGTx5auK5C/mFOyIUJZccxoNm3UyjVbjOYqFRv1s524Jnjr1tec 2s4jmTR9UcmAmltIB/Tdk6GUHQeL1yjq7BhbgeBodSz78rW7XVhwhZPvqz2tPzdNXIpG R3akk4eStpSXZmPc2W7J5v0jDmwWVsan2Sw/4LqZQCSSfXGITYnbxwks0eZegE6BiET4 Yx4zWx13f1lsdACriFnMDG+rhhRH+LEMZZ3zqyYJk82Fv94bFqBgqm0mv+QZpFF3kiUn CfkQ== X-Gm-Message-State: AOJu0Yx1Mqq72c4+isiw3pIGOwqUP+9JeHpvsNDWeYKJmLV+BWxTWdCr wrMaoC1895REW7aCkIFr7WvmcnY09qATJHhI/DKU7V8Yu/jW25pGxocRiFZ6igXRPcSk7zmqHzW ltjNJRN8v/vXEvXmNgAP9FFUH3wWxtnY4vVT+AlrZuj2JhVCRhINg1exVzv6YnZBrJNNdtmc9Fe TTVz5inaJkpHC6Yzhtsy5QyWSVVwW4aCunsv1rgnPc X-Gm-Gg: Acq92OElIgEQr+ReCFwH16ZLn4ChgRVGDkjtpMqlSZ3eG96c46gjBe0/F0u605IYE7P w+dPxHiXRpGk4/1xSNyr5x25in51zTIsrknPie6BHa7/4CEoqXwD+O+PpvAdmoI143WgQdiL1Uz TSJRJDGf57OfTpAXC+OxbOnxsYx2tBiN6VZ5uKHsDetmD6KvEgNymnaFJ+EtpVcTmuYjlD6gp95 E9tN/SABBolMC/qA2qPRhCTp2wPYKbTWVjRBW5B1kea2Hx/5EA5eF98/GbJwwFuHdH9BYoZ5GxM L4tH3ricCI3dcGi5DRYB7ZCY371hBNZbLJxcGMQZc1O3cU4xRe0WJKNAdeswv5+am2dgJLFk7CE jSjXlMCryosDIQ7FC/naqKLV1jIuvD8OGKqKzdG0Mhw85UKP7tS6olXUALM+RXkaSDpZk3i+oB8 Ch1oswak37/E2GU3zF/VhYEdHndyk= X-Received: by 2002:a05:600c:4e4b:b0:485:46fd:7887 with SMTP id 5b1f17b1804b1-49069da6188mr117648095e9.13.1779818224274; Tue, 26 May 2026 10:57:04 -0700 (PDT) X-Received: by 2002:a05:600c:4e4b:b0:485:46fd:7887 with SMTP id 5b1f17b1804b1-49069da6188mr117647655e9.13.1779818223672; Tue, 26 May 2026 10:57:03 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 15/19] scripts/qapi: generate high-level Rust bindings Date: Tue, 26 May 2026 19:56:14 +0200 Message-ID: <20260526175618.227743-16-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818362111154100 From: Marc-Andr=C3=A9 Lureau Generate high-level native Rust declarations for the QAPI types. - char* is mapped to String, scalars to there corresponding Rust types - enums use #[repr(u32)] and can be transmuted to their C counterparts - has_foo/foo members are mapped to Option - lists are represented as Vec - structures map fields 1:1 to Rust - alternate are represented as Rust enum, each variant being a 1-element tuple - unions are represented in a similar way as in C: a struct S with a "u" member (since S may have extra 'base' fields). The discriminant isn't a member of S, since Rust enum already include it, but it can be recovered with "mystruct.u.into()" Anything that includes a recursive struct puts it in a Box. Lists are not considered recursive, because Vec breaks the recursion (it's possible to construct an object containing an empty Vec of its own type). Given the experimental nature of Rust, and the incompleteness of the backend (it lacks commands and events), QAPIRsBackend is not modular and is not built together with the C and trace-event files. It can be used by specifying "-B qapi.backend.QAPIRsBackend" on the qapi-gen command line. Signed-off-by: Marc-Andr=C3=A9 Lureau Link: https://lore.kernel.org/r/20210907121943.3498701-21-marcandre.lureau@= redhat.com [Paolo: rewrite conversion of leaf types] Signed-off-by: Paolo Bonzini --- meson.build | 4 +- scripts/qapi/backend.py | 25 +++ scripts/qapi/common.py | 49 ++++++ scripts/qapi/rs.py | 50 ++++++ scripts/qapi/rs_types.py | 372 +++++++++++++++++++++++++++++++++++++++ scripts/qapi/schema.py | 59 +++++-- 6 files changed, 540 insertions(+), 19 deletions(-) create mode 100644 scripts/qapi/rs.py create mode 100644 scripts/qapi/rs_types.py diff --git a/meson.build b/meson.build index eb074918193..bda5180c436 100644 --- a/meson.build +++ b/meson.build @@ -3485,11 +3485,13 @@ qapi_gen_depends =3D [ meson.current_source_dir() /= 'scripts/qapi/__init__.py', meson.current_source_dir() / 'scripts/qapi/introspect= .py', meson.current_source_dir() / 'scripts/qapi/main.py', meson.current_source_dir() / 'scripts/qapi/parser.py', + meson.current_source_dir() / 'scripts/qapi/rs_types.p= y', meson.current_source_dir() / 'scripts/qapi/schema.py', meson.current_source_dir() / 'scripts/qapi/source.py', meson.current_source_dir() / 'scripts/qapi/types.py', meson.current_source_dir() / 'scripts/qapi/visit.py', - meson.current_source_dir() / 'scripts/qapi-gen.py' + meson.current_source_dir() / 'scripts/qapi-gen.py', + meson.current_source_dir() / 'scripts/qapi/rs.py', ] =20 tracetool =3D [ diff --git a/scripts/qapi/backend.py b/scripts/qapi/backend.py index 49ae6ecdd33..8023acce0d6 100644 --- a/scripts/qapi/backend.py +++ b/scripts/qapi/backend.py @@ -7,6 +7,7 @@ from .events import gen_events from .features import gen_features from .introspect import gen_introspect +from .rs_types import gen_rs_types from .schema import QAPISchema from .types import gen_types from .visit import gen_visit @@ -63,3 +64,27 @@ def generate(self, gen_commands(schema, output_dir, prefix, gen_tracing) gen_events(schema, output_dir, prefix) gen_introspect(schema, output_dir, prefix, unmask) + + +class QAPIRsBackend(QAPIBackend): + # pylint: disable=3Dtoo-few-public-methods + + def generate(self, + schema: QAPISchema, + output_dir: str, + prefix: str, + unmask: bool, + builtins: bool, + gen_tracing: bool) -> None: + """ + Generate Rust code for the given schema into the target directory. + + :param schema_file: The primary QAPI schema file. + :param output_dir: The output directory to store generated code. + :param prefix: Optional C-code prefix for symbol names. + :param unmask: Expose non-ABI names through introspection? + :param builtins: Generate code for built-in types? + + :raise QAPIError: On failures. + """ + gen_rs_types(schema, output_dir, prefix) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 44229c2e366..67a4b11e4f3 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -64,6 +64,13 @@ def camel_to_upper(value: str) -> str: return ret.upper() =20 =20 +def camel_to_lower(value: str) -> str: + """ + Converts CamelCase to camel_case. + """ + return camel_to_upper(value).lower() + + def c_enum_const(type_name: str, const_name: str, prefix: Optional[str] =3D None) -> str: @@ -129,6 +136,48 @@ def c_name(name: str, protect: bool =3D True) -> str: return name =20 =20 +def rs_name(name: str) -> str: + """ + Map @name to a valid, possibly raw Rust identifier. + """ + name =3D re.sub(r'[^A-Za-z0-9_]', '_', name) + if name[0].isnumeric(): + name =3D '_' + name + # based from the list: + # https://doc.rust-lang.org/reference/keywords.html + if name in ('Self', 'abstract', 'as', 'async', + 'await', 'become', 'box', 'break', + 'const', 'continue', 'crate', 'do', + 'dyn', 'else', 'enum', 'extern', + 'false', 'final', 'fn', 'for', + 'if', 'impl', 'in', 'let', + 'loop', 'macro', 'match', 'mod', + 'move', 'mut', 'override', 'priv', + 'pub', 'ref', 'return', 'self', + 'static', 'struct', 'super', 'trait', + 'true', 'try', 'type', 'typeof', + 'union', 'unsafe', 'unsized', 'use', + 'virtual', 'where', 'while', 'yield'): + name =3D 'r#' + name + + return name + + +def to_camel_case(value: str) -> str: + result =3D '' + for p in re.split(r'[-_]+', value): + if not p: + pass + elif p[0].isalpha(): + result +=3D p[0].upper() + p[1:] + elif result and result[-1].isalpha(): + result +=3D p + else: + # digit_digit, or digit at start of value + result +=3D '_' + p + return result + + class Indentation: """ Indentation level management. diff --git a/scripts/qapi/rs.py b/scripts/qapi/rs.py new file mode 100644 index 00000000000..ad32b527cd6 --- /dev/null +++ b/scripts/qapi/rs.py @@ -0,0 +1,50 @@ +# This work is licensed under the terms of the GNU GPL, version 2. +# See the COPYING file in the top-level directory. +""" +QAPI Rust generator +""" + +import os +import re +import sys + +from .common import mcgen +from .gen import QAPIGen +from .schema import QAPISchemaVisitor + + +class QAPIGenRs(QAPIGen): + def __init__(self, fname: str, blurb: str, pydoc: str): + super().__init__(fname) + self._blurb =3D blurb + self._copyright =3D '\n//! '.join(re.findall(r'^Copyright .*', pyd= oc, + re.MULTILINE)) + + def _top(self) -> str: + return mcgen(''' +// @generated by qapi-gen, DO NOT EDIT + +//! +//! %(blurb)s +//! +//! %(copyright)s +//! +//! This work is licensed under the terms of the GNU LGPL, version 2.1 or +//! later. See the COPYING.LIB file in the top-level directory. + +''', + tool=3Dos.path.basename(sys.argv[0]), + blurb=3Dself._blurb, copyright=3Dself._copyright) + + +class QAPISchemaRsVisitor(QAPISchemaVisitor): + + def __init__(self, prefix: str, what: str, + blurb: str, pydoc: str): + super().__init__() + self._prefix =3D prefix + self._what =3D what + self._gen =3D QAPIGenRs(self._prefix + self._what + '.rs', blurb, = pydoc) + + def write(self, output_dir: str) -> None: + self._gen.write(output_dir) diff --git a/scripts/qapi/rs_types.py b/scripts/qapi/rs_types.py new file mode 100644 index 00000000000..874ebdbfa41 --- /dev/null +++ b/scripts/qapi/rs_types.py @@ -0,0 +1,372 @@ +# This work is licensed under the terms of the GNU GPL, version 2. +# See the COPYING file in the top-level directory. +""" +QAPI Rust types generator + +Copyright (c) 2025 Red Hat, Inc. + +This work is licensed under the terms of the GNU GPL, version 2. +See the COPYING file in the top-level directory. +""" + +from typing import List, Optional, Set + +from .common import ( + camel_to_lower, + camel_to_upper, + mcgen, + rs_name, + to_camel_case, +) +from .rs import QAPISchemaRsVisitor +from .schema import ( + QAPISchema, + QAPISchemaAlternateType, + QAPISchemaEnumMember, + QAPISchemaFeature, + QAPISchemaIfCond, + QAPISchemaObjectType, + QAPISchemaObjectTypeMember, + QAPISchemaType, + QAPISchemaVariants, +) +from .source import QAPISourceInfo + + +objects_seen =3D set() + + +def gen_rs_variants_to_tag(name: str, + ifcond: QAPISchemaIfCond, + variants: QAPISchemaVariants) -> str: + ret =3D mcgen(''' + +%(cfg)s''', ''' +impl From<&%(rs_name)sVariant> for %(tag)s { + fn from(e: &%(rs_name)sVariant) -> Self { + match e { +''', + cfg=3Difcond.rsgen(), + rs_name=3Drs_name(name), + tag=3Dvariants.tag_member.type.rs_type()) + + for var in variants.variants: + type_name =3D var.type.name + tag_name =3D var.name + patt =3D '(_)' + if type_name =3D=3D 'q_empty': + patt =3D '' + ret +=3D mcgen(''' + %(cfg)s''', ''' + %(rs_name)sVariant::%(var_name)s%(patt)s =3D> Self::%(tag_name= )s, +''', + cfg=3Dvar.ifcond.rsgen(), + rs_name=3Drs_name(name), + tag_name=3Drs_name(camel_to_upper(tag_name)), + var_name=3Drs_name(to_camel_case(tag_name)), + patt=3Dpatt) + + ret +=3D mcgen(''' + } + } +} +''') + return ret + + +def gen_rs_variants(name: str, + ifcond: QAPISchemaIfCond, + variants: QAPISchemaVariants) -> str: + ret =3D mcgen(''' + +%(cfg)s''', ''' +#[derive(Clone, Debug, PartialEq)] +pub enum %(rs_name)sVariant {''', + cfg=3Difcond.rsgen(), + rs_name=3Drs_name(name)) + + for var in variants.variants: + type_name =3D var.type.name + var_name =3D rs_name(to_camel_case(var.name)) + if type_name =3D=3D 'q_empty': + ret +=3D mcgen(''' + %(cfg)s''', ''' + %(var_name)s, +''', + cfg=3Dvar.ifcond.rsgen(), + var_name=3Dvar_name) + else: + ret +=3D mcgen(''' + %(cfg)s''', ''' + %(var_name)s(%(rs_type)s), +''', + cfg=3Dvar.ifcond.rsgen(), + var_name=3Dvar_name, + rs_type=3Dvar.type.rs_type()) + + ret +=3D mcgen(''' +} +''') + + ret +=3D gen_rs_variants_to_tag(name, ifcond, variants) + + return ret + + +def gen_rs_members(members: List[QAPISchemaObjectTypeMember], + exclude: Optional[List[str]] =3D None) -> List[str]: + exclude =3D exclude or [] + return [f"{m.ifcond.rsgen()} {rs_name(camel_to_lower(m.name))}" + for m in members if m.name not in exclude] + + +def has_recursive_type(memb: QAPISchemaType, + name: str, + visited: Set[str]) -> bool: + # pylint: disable=3Dtoo-many-return-statements + if name =3D=3D memb.name: + return True + if memb.name in visited: + return False + visited.add(memb.name) + if isinstance(memb, QAPISchemaObjectType): + if memb.base and has_recursive_type(memb.base, name, visited): + return True + if memb.branches and \ + any(has_recursive_type(m.type, name, visited) + for m in memb.branches.variants): + return True + if any(has_recursive_type(m.type, name, visited) + for m in memb.members): + return True + return any(has_recursive_type(m.type, name, visited) + for m in memb.local_members) + if isinstance(memb, QAPISchemaAlternateType): + return any(has_recursive_type(m.type, name, visited) + for m in memb.alternatives.variants) + return False + + +def gen_struct_members(members: List[QAPISchemaObjectTypeMember], + name: str) -> str: + ret =3D [] + for memb in members: + typ =3D memb.type.rs_type() + if has_recursive_type(memb.type, name, set()): + typ =3D 'Box<%s>' % typ + if memb.optional: + typ =3D 'Option<%s>' % typ + ret.append(mcgen(''' +%(cfg)s''', ''' + pub %(rs_name)s: %(rs_type)s, +''', + cfg=3Dmemb.ifcond.rsgen(), + rs_type=3Dtyp, + rs_name=3Drs_name(camel_to_lower(memb.name)))) + return '\n'.join(ret) + + +def gen_rs_object(name: str, + ifcond: QAPISchemaIfCond, + base: Optional[QAPISchemaObjectType], + members: List[QAPISchemaObjectTypeMember], + variants: Optional[QAPISchemaVariants]) -> str: + if name in objects_seen: + return '' + + if variants: + members =3D [m for m in members + if m.name !=3D variants.tag_member.name] + + ret =3D '' + objects_seen.add(name) + + if variants: + ret +=3D gen_rs_variants(name, ifcond, variants) + + ret +=3D mcgen(''' + +%(cfg)s''', ''' +#[derive(Clone, Debug, PartialEq)]''', ''' +pub struct %(rs_name)s { +''', + cfg=3Difcond.rsgen(), + rs_name=3Drs_name(name)) + + if base: + if not base.is_implicit(): + ret +=3D mcgen(''' + // Members inherited: +''', + c_name=3Dbase.c_name()) + base_members =3D base.members + if variants: + base_members =3D [m for m in base.members + if m.name !=3D variants.tag_member.name] + ret +=3D gen_struct_members(base_members, name) + if not base.is_implicit(): + ret +=3D mcgen(''' + // Own members: +''') + + ret +=3D gen_struct_members(members, name) + + if variants: + ret +=3D mcgen(''' + pub u: %(rs_type)sVariant, +''', rs_type=3Drs_name(name)) + ret +=3D mcgen(''' +} +''') + return ret + + +def gen_rs_enum(name: str, + ifcond: QAPISchemaIfCond, + members: List[QAPISchemaEnumMember]) -> str: + ret =3D mcgen(''' + +%(cfg)s''', ''' +#[derive(Copy, Clone, Debug, PartialEq)] +''', + cfg=3Difcond.rsgen()) + + if members: + ret +=3D '''#[repr(u32)] +#[derive(common::TryInto)] +''' + ret +=3D mcgen(''' +pub enum %(rs_name)s {''', + rs_name=3Drs_name(name)) + + for member in members: + ret +=3D mcgen(''' + %(cfg)s''', ''' + %(c_enum)s, +''', + cfg=3Dmember.ifcond.rsgen(), + c_enum=3Drs_name(camel_to_upper(member.name))) + ret +=3D '''} + +''' + + # pick the first, since that's what malloc0 does + if not members[0].ifcond.is_present(): + default =3D rs_name(camel_to_upper(members[0].name)) + ret +=3D mcgen(''' +%(cfg)s''', ''' +impl Default for %(rs_name)s { + #[inline] + fn default() -> %(rs_name)s { + Self::%(default)s + } +} +''', + cfg=3Difcond.rsgen(), + rs_name=3Drs_name(name), + default=3Ddefault) + return ret + + +def gen_rs_alternate(name: str, + ifcond: QAPISchemaIfCond, + variants: QAPISchemaVariants) -> str: + if name in objects_seen: + return '' + + ret =3D '' + objects_seen.add(name) + + ret +=3D mcgen(''' +%(cfg)s''', ''' +#[derive(Clone, Debug, PartialEq)] +pub enum %(rs_name)s { +''', + cfg=3Difcond.rsgen(), + rs_name=3Drs_name(name)) + + for var in variants.variants: + if var.type.name =3D=3D 'q_empty': + continue + typ =3D var.type.rs_type() + if has_recursive_type(var.type, name, set()): + typ =3D 'Box<%s>' % typ + ret +=3D mcgen(''' + %(cfg)s''', ''' + %(mem_name)s(%(rs_type)s), +''', + cfg=3Dvar.ifcond.rsgen(), + rs_type=3Dtyp, + mem_name=3Drs_name(to_camel_case(var.name))) + + ret +=3D mcgen(''' +} +''') + return ret + + +class QAPISchemaGenRsTypeVisitor(QAPISchemaRsVisitor): + _schema: Optional[QAPISchema] + + def __init__(self, prefix: str) -> None: + super().__init__(prefix, 'qapi-types', + 'Schema-defined QAPI types', __doc__) + + def visit_begin(self, schema: QAPISchema) -> None: + self._schema =3D schema + objects_seen.add(schema.the_empty_object_type.name) + + self._gen.preamble_add( + mcgen(''' +#![allow(unexpected_cfgs)] +#![allow(non_camel_case_types)] +#![allow(clippy::empty_structs_with_brackets)] +#![allow(clippy::large_enum_variant)] +#![allow(clippy::pub_underscore_fields)] + +// Because QAPI structs can contain float, for simplicity we never +// derive Eq. Clippy however would complain for those structs +// that *could* be Eq too. +#![allow(clippy::derive_partial_eq_without_eq)] + +use util::qobject::QObject; +''')) + + def visit_object_type(self, + name: str, + info: Optional[QAPISourceInfo], + ifcond: QAPISchemaIfCond, + features: List[QAPISchemaFeature], + base: Optional[QAPISchemaObjectType], + members: List[QAPISchemaObjectTypeMember], + branches: Optional[QAPISchemaVariants]) -> None: + assert self._schema is not None + if self._schema.is_predefined(name) or name.startswith('q_'): + return + self._gen.add(gen_rs_object(name, ifcond, base, members, branches)) + + def visit_enum_type(self, + name: str, + info: Optional[QAPISourceInfo], + ifcond: QAPISchemaIfCond, + features: List[QAPISchemaFeature], + members: List[QAPISchemaEnumMember], + prefix: Optional[str]) -> None: + assert self._schema is not None + if self._schema.is_predefined(name): + return + self._gen.add(gen_rs_enum(name, ifcond, members)) + + def visit_alternate_type(self, + name: str, + info: Optional[QAPISourceInfo], + ifcond: QAPISchemaIfCond, + features: List[QAPISchemaFeature], + alternatives: QAPISchemaVariants) -> None: + self._gen.add(gen_rs_alternate(name, ifcond, alternatives)) + + +def gen_rs_types(schema: QAPISchema, output_dir: str, prefix: str) -> None: + vis =3D QAPISchemaGenRsTypeVisitor(prefix) + schema.visit(vis) + vis.write(output_dir) diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index 3459b8038e5..3cfe9bbc21d 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -37,6 +37,7 @@ docgen_ifcond, gen_endif, gen_if, + rs_name, rsgen_ifcond, ) from .error import QAPIError, QAPISemError, QAPISourceError @@ -341,6 +342,11 @@ def c_param_type(self) -> str: def c_unboxed_type(self) -> str: return self.c_type() =20 + # Return the Rust type for common use + @abstractmethod + def rs_type(self) -> str: + pass + @abstractmethod def json_type(self) -> str: pass @@ -382,11 +388,12 @@ def describe(self) -> str: class QAPISchemaBuiltinType(QAPISchemaType): meta =3D 'built-in' =20 - def __init__(self, name: str, json_type: str, c_type: str): + def __init__(self, name: str, json_type: str, rs_type: str, c_type: st= r): super().__init__(name, None, None) assert json_type in ('string', 'number', 'int', 'boolean', 'null', 'value') self._json_type_name =3D json_type + self._rs_type_name =3D rs_type self._c_type_name =3D c_type =20 def c_name(self) -> str: @@ -406,6 +413,9 @@ def json_type(self) -> str: def doc_type(self) -> str: return self.json_type() =20 + def rs_type(self) -> str: + return self._rs_type_name + def visit(self, visitor: QAPISchemaVisitor) -> None: super().visit(visitor) visitor.visit_builtin_type(self.name, self.info, self.json_type()) @@ -453,6 +463,9 @@ def is_implicit(self) -> bool: def c_type(self) -> str: return c_name(self.name) =20 + def rs_type(self) -> str: + return rs_name(self.name) + def member_names(self) -> List[str]: return [m.name for m in self.members] =20 @@ -502,6 +515,9 @@ def is_implicit(self) -> bool: def c_type(self) -> str: return c_name(self.name) + POINTER_SUFFIX =20 + def rs_type(self) -> str: + return 'Vec<%s>' % self.element_type.rs_type() + def json_type(self) -> str: return 'array' =20 @@ -634,6 +650,9 @@ def c_type(self) -> str: def c_unboxed_type(self) -> str: return c_name(self.name) =20 + def rs_type(self) -> str: + return rs_name(self.name) + def json_type(self) -> str: return 'object' =20 @@ -715,6 +734,9 @@ def c_type(self) -> str: def json_type(self) -> str: return 'value' =20 + def rs_type(self) -> str: + return rs_name(self.name) + def visit(self, visitor: QAPISchemaVisitor) -> None: super().visit(visitor) visitor.visit_alternate_type( @@ -1246,9 +1268,10 @@ def _def_include(self, expr: QAPIExpression) -> None: QAPISchemaInclude(self._make_module(include), expr.info)) =20 def _def_builtin_type( - self, name: str, json_type: str, c_type: str + self, name: str, json_type: str, rs_type: str, c_type: str ) -> None: - self._def_definition(QAPISchemaBuiltinType(name, json_type, c_type= )) + builtin =3D QAPISchemaBuiltinType(name, json_type, rs_type, c_type) + self._def_definition(builtin) # Instantiating only the arrays that are actually used would # be nice, but we can't as long as their generated code # (qapi-builtin-types.[ch]) may be shared by some other @@ -1267,21 +1290,21 @@ def is_predefined(self, name: str) -> bool: return False =20 def _def_predefineds(self) -> None: - for t in [('str', 'string', 'char' + POINTER_SUFFIX), - ('number', 'number', 'double'), - ('int', 'int', 'int64_t'), - ('int8', 'int', 'int8_t'), - ('int16', 'int', 'int16_t'), - ('int32', 'int', 'int32_t'), - ('int64', 'int', 'int64_t'), - ('uint8', 'int', 'uint8_t'), - ('uint16', 'int', 'uint16_t'), - ('uint32', 'int', 'uint32_t'), - ('uint64', 'int', 'uint64_t'), - ('size', 'int', 'uint64_t'), - ('bool', 'boolean', 'bool'), - ('any', 'value', 'QObject' + POINTER_SUFFIX), - ('null', 'null', 'QNull' + POINTER_SUFFIX)]: + for t in [('str', 'string', 'String', 'char' + POINTER_SUFFIX= ), + ('number', 'number', 'f64', 'double'), + ('int', 'int', 'i64', 'int64_t'), + ('int8', 'int', 'i8', 'int8_t'), + ('int16', 'int', 'i16', 'int16_t'), + ('int32', 'int', 'i32', 'int32_t'), + ('int64', 'int', 'i64', 'int64_t'), + ('uint8', 'int', 'u8', 'uint8_t'), + ('uint16', 'int', 'u16', 'uint16_t'), + ('uint32', 'int', 'u32', 'uint32_t'), + ('uint64', 'int', 'u64', 'uint64_t'), + ('size', 'int', 'u64', 'uint64_t'), + ('bool', 'boolean', 'bool', 'bool'), + ('any', 'value', 'QObject', 'QObject' + POINTER_SUF= FIX), + ('null', 'null', '()', 'QNull' + POINTER_SUFFI= X)]: self._def_builtin_type(*t) self.the_empty_object_type =3D QAPISchemaObjectType( 'q_empty', None, None, None, None, None, [], None) --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818249; cv=none; d=zohomail.com; s=zohoarc; b=R5R6rP+osyWZ/8r5o+4FEil7HnUgCPmLvsJaP4kQ2AetezWD0qcapul33EMq3X9ODO+4EvT9wS52nUYtQ43n+QoARmkecOWUaug6Fw2hHcAtSw1nfNEDO5lkuFbYE15yxyN3XeMAQtj032zyZR5PQFqRXUJjeW53wuq2euOsp6w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818249; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Wd46RPv1cpVjcJdKvZTejd8Ngdtpj1qfzxjn3ahDdkA=; b=IQIUfLivk3ptr+AckS2y9XSIoU1xNQjgmXQoDVLQAM4beSiNh3PYxz5cr7hinD4Bg/mt7KBk7/QyWDMStyDTq+eELD91Td91Qt3y3cwZbOVIJzfF2pEIcLK4YwEv9Oca8PGXoO4Z7jY5INj4Q3ZronlHxXSkBOWl/cSjF7Co/6E= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818249588621.1521961530615; Tue, 26 May 2026 10:57:29 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1j-0002Hp-Fc; Tue, 26 May 2026 13:57:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1e-0002AS-Js for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:10 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1c-00085M-ST for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:10 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-530-rBakSNYtOI6saAAE1_0lkw-1; Tue, 26 May 2026 13:57:06 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-48fe40b61a3so70758055e9.3 for ; Tue, 26 May 2026 10:57:06 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6d6ebf0sm38630648f8f.34.2026.05.26.10.57.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:57:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818228; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Wd46RPv1cpVjcJdKvZTejd8Ngdtpj1qfzxjn3ahDdkA=; b=C7w8YuuyDxu8LbJ9Jk4dzwjt5kkwia5MoBAFBAFOq19DTL8ykXxfrIVTEuflvypi62Soqw aNOOMywFwKALv5EUaJLw9y/FoG8QnaDxhIcEUPlCGJhED5gBBn23V8pH5MXqVAzqY/7+Dz GAHMsto5j9QbAbe9Kui2ElZtGNWf7HM= X-MC-Unique: rBakSNYtOI6saAAE1_0lkw-1 X-Mimecast-MFC-AGG-ID: rBakSNYtOI6saAAE1_0lkw_1779818225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818225; x=1780423025; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Wd46RPv1cpVjcJdKvZTejd8Ngdtpj1qfzxjn3ahDdkA=; b=Nw/oCQjH8nEknobK1xOVpUo1TXhH4f8t6dBnP2LarimGQS/6Il6KwFN0uCcqq1s7u/ 3kEHGmyp7ehzDfnH2aQMPFQsilBHghi+JRR1mOq0rJKSAyE0EnBY38jxcLsIThD9vz0h xNUyMLN28VWRvqrLc5wmcbYqhIihu5Lx4AFpSAOavKPdwWTq7588GpnuuW6kuzfh3Pgs oHq5oeh1OAgP0KK+E35aunZEAI0iYwU2nOWQ9r1COnFMv0E49cbrCX0EqBStKDdMF+qF TL4EKRYyEpygeTRF+yS/sQizM/p/gZUAShZK8ieYNFiY7Y4tBgxks5wUQh1qxy+BScrT FlCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818225; x=1780423025; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Wd46RPv1cpVjcJdKvZTejd8Ngdtpj1qfzxjn3ahDdkA=; b=hbbMwGTUYAGE/64Xr7vPlVaY210ruAClBSOCBHV3kKYyu3N/9F4b0VofDbSzwGZ5jG Ynb97a+Oig6u1wpDQPLDiURjvB+TAGJLR9UbDJ9eGhSt7Wllvby1gAxZeP+4M6h1/f0r qbPY9GsvcN9r2LxOnvXoKFIY2YwUHCXv0mTQQWxc3nRLDKrw3r+dYKOuhiz8nDA9lcxR pe7N2OXzz2/vZ6T+ayesAd4B2UvPtOLWHr3zXNJdRF6KYNS61q7HwQ1fDt7RE+TLkkX3 NMsVJrek5tKtGcHD2g0Nxa/xjuRMfNm9zx+eVKXntF6HBQwlOa/W+BA+2MHFJ4lhLOD3 3AEQ== X-Gm-Message-State: AOJu0YyBxSzykV2bvweUhHa6/cn9kzSB08x4fTT4SngcGSKtxxKKsvZx nSmcYrzUgU14D/Qat8fFzd7cVsZJ0L0mYCJTsK914Li99wU79ejHiAa92V/nj8NO/NwrkdWynT1 tKNtzWMSjs4Lm/6muuBo4ZhlIp5oxXBYAfwgbkn/BVSRXBrcUkK+lxGyC770kXDJpG2I39LSrVt /JJVldarR7TOImJW+T11WWH3IJIbkxo2KzIIaFxgbF X-Gm-Gg: Acq92OGkyNz/CTgWVUEWkyjeNusB64Ka4KQX5gA6XkjTwIPnZE1e+rM5Xqktb0HcDvs 1ZQNvTBJLGuVGg48dpq7edYmkdCYTl7hZ2wkzrDWYDroZ+qWBbUqC8RHwYd3AxmTZNUsLAAXNqn PTw74cBPH3QguCElM2P3JE7z8PjRoWjn64lW/ihcq8fspBgUINmQLrGeCmqSAVRMlmT5ib3GqpV 4Ezr/KQGbHrbfKh0nDaISZtgFbKMTOizytqucA13J4tj0n0vQWMohs75Sp3y3LY471GPZjN8FO6 KEr/RBZ+Fa88KWnH0kN6DnvU2CnM8Asr+WDiKj41T/I8Q+BMVgup8d505TQZLkIiRL5r+24fshH NcXeiqznYekA6yA7WguJm5Q+RhwXqAOQDb8z8+Gr4TN7xJSKKzP0bKWYR5XKYYnl++HQRHOHZ6o gEUBcdzW/+S/qLlYIe7rcfJOxeVlY= X-Received: by 2002:a05:600d:6414:20b0:490:4b89:5359 with SMTP id 5b1f17b1804b1-4904b895514mr211213435e9.1.1779818225520; Tue, 26 May 2026 10:57:05 -0700 (PDT) X-Received: by 2002:a05:600d:6414:20b0:490:4b89:5359 with SMTP id 5b1f17b1804b1-4904b895514mr211213235e9.1.1779818225105; Tue, 26 May 2026 10:57:05 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 16/19] scripts/rustc_args: add --no-strict-cfg Date: Tue, 26 May 2026 19:56:15 +0200 Message-ID: <20260526175618.227743-17-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818252196154100 From: Marc-Andr=C3=A9 Lureau Allow to generate all --cfg flags, regardless of Cargo.toml content. We can't easily list and include all the features used by QAPI types. Access via #[cfg()] then requires #![allow(unexpected_cfgs)]. Signed-off-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Paolo Bonzini --- scripts/rust/rustc_args.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/rust/rustc_args.py b/scripts/rust/rustc_args.py index 8098053720a..6a156b9608e 100644 --- a/scripts/rust/rustc_args.py +++ b/scripts/rust/rustc_args.py @@ -108,7 +108,7 @@ def generate_lint_flags(cargo_toml: CargoTOML) -> Itera= ble[str]: yield from lint.flags =20 =20 -def generate_cfg_flags(header: str, cargo_toml: CargoTOML) -> Iterable[str= ]: +def generate_cfg_flags(header: str, cargo_toml: Optional[CargoTOML]) -> It= erable[str]: """Converts defines from config[..].h headers to rustc --cfg flags.""" =20 with open(header, encoding=3D"utf-8") as cfg: @@ -117,8 +117,9 @@ def generate_cfg_flags(header: str, cargo_toml: CargoTO= ML) -> Iterable[str]: cfg_list =3D [] for cfg in config: name =3D cfg[0] - if f'cfg({name})' not in cargo_toml.check_cfg: - continue + if cargo_toml: + if f'cfg({name})' not in cargo_toml.check_cfg: + continue if len(cfg) >=3D 2 and cfg[1] !=3D "1": continue cfg_list.append("--cfg") @@ -179,6 +180,13 @@ def main() -> None: required=3DFalse, default=3D"1.0.0", ) + parser.add_argument( + "--no-strict-cfg", + help=3D"only generate expected cfg", + action=3D"store_false", + dest=3D"strict_cfg", + default=3DTrue, + ) args =3D parser.parse_args() if args.verbose: logging.basicConfig(level=3Dlogging.DEBUG) @@ -209,7 +217,7 @@ def main() -> None: print(f'cfg(feature,values("{feature}"))') =20 for header in args.config_headers: - for tok in generate_cfg_flags(header, cargo_toml): + for tok in generate_cfg_flags(header, cargo_toml if args.strict_cf= g else None): print(tok) =20 =20 --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818313; cv=none; d=zohomail.com; s=zohoarc; b=OglFJrWY3AdRX+CBzWxz0zST6dIOoPZpkBM1nytPKdGob9UpJxuIDTu4riguJEOUf5XYHSclj5nhqGZMgM4OdIhb5Lvn7tVykkU9RhF9cyQ6MAw70YOTbDH6JkG6+jA0B7tN3gZmBcv+eV7Zi/C7JFXzo8ouTItPISdr27FPBDQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818313; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=iyZOn8vowMt4BCTJvMxz9ts52f+qcFqcdwze56Aj1uE=; b=DFt8cJwMerFdGqTzWI2D/neuXgBFrvhRs2pRhwzpLBpoFR1Cozx+R28LNKdaxYXlTYG3DYIKXWFBP8k80eFn2zVi3lWp/nDPSFWXzFH7NtYo6rk0iatAvWnGI2smQhtNhevaEHPoddR2b4o1oIysD+AuNUAcDeoCvc19FWibOI0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818312977728.151716163727; Tue, 26 May 2026 10:58:32 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1k-0002JM-Kf; Tue, 26 May 2026 13:57:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1g-0002EL-KC for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:14 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1e-00085r-KI for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:12 -0400 Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-587-xa0KSzCbMJu-mhIAemwL3Q-1; Tue, 26 May 2026 13:57:07 -0400 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-4518f777225so7723214f8f.1 for ; Tue, 26 May 2026 10:57:07 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6d47b82sm37377299f8f.19.2026.05.26.10.57.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:57:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818229; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iyZOn8vowMt4BCTJvMxz9ts52f+qcFqcdwze56Aj1uE=; b=Vv2fInNfeOk4FJuUIXNr8eYtjSZsgeZ7XYZLbp5FO9b1V8UWgZhyiMELULr3AETS6zAR/H /PkzB3x2Ru6Pl+FjGlYsy7ro5JUTarmrQ8IOhcigwKkeQN/692eRugC9J05CMocEvMfFs3 Z03kyvC4qNShSrVKVJw9cixTQaXZeCA= X-MC-Unique: xa0KSzCbMJu-mhIAemwL3Q-1 X-Mimecast-MFC-AGG-ID: xa0KSzCbMJu-mhIAemwL3Q_1779818227 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818226; x=1780423026; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=iyZOn8vowMt4BCTJvMxz9ts52f+qcFqcdwze56Aj1uE=; b=JAI5dgBlr9ngCBRLObyIBio9XXv21sQnWJMYsAddJUrBhD6XXHQ8svz7uPdiYM4QBK nsqvfk4/e48LjxjxjKyb3lBrmZNF7ERyC3X7cAhiRSNY2pgarbZ52wAA7jRJQDxNe4Ej L6zsfj+XAmi+U2zuzms1knpd2I8BkhrHETCrG0225VW1CoKr+4yFWkrWU25t1ox9b0db fkiI23btXe3iHhYwRaswFvtm+6U882kPPo4B0pabF5b+I+4MIC8HrPW8uoGK4inapGOW 5PkomFaI4nzlwBqh9SQmAA0ClWNZ1I5NYLf7F9okphj6E/ypTUsWU2w6V+xlqXkS2pET foOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818226; x=1780423026; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=iyZOn8vowMt4BCTJvMxz9ts52f+qcFqcdwze56Aj1uE=; b=TpAmv4a+X3U+aZmjBA18Eu+R/e1+tNloBL55CBy/PcGVdlCfbkF3X+m30pp/4bnNCw 9s1E9PApARXRpQezKqM7YTFF2mGarHUISn/AWgOYtQ+uWdspF9LPL5jnt9XpzvNlPa8Y SlDj/I5NriSmVvI8k6p729oIqC7hVuu+SP8hYxMpj1XO105JqzLWiTWBbw8ii+98sGqM QiXSZLfddvrvt1Iu5jxLgcd9ivQK+SIbvYDpGEK0/qzXzHTVXwtXn7DA+QKW+mC8DF8h 5iqMs3Uw8SjRmyFXl8g6oRV32Vck2YvlFHOOabu5i0Cs5fwugSEpxwk/lNtjnTMJ+Yu0 TB0w== X-Gm-Message-State: AOJu0Yxh7WWazBMiKxs7wAOXzF+7wSLlnE4pN5bcnoca1XdJdhUr5MLx 85qLJ640GLqb96sFo53sj9xnEVrr74cvWTMyHq3FlQd3N0okIUXq0PKl0UVNRcUdmH0rgMbWU88 ZyL7oxK3omUMKRtPVsudSnHq3d5iCdUP0IHARbTdP7iN7nqSd6bSWHW/sHrXwol32Q5IQiY8cx7 ogSwXC+yAhxaCitjloH9eJi0NQ1AgAnO8YXRZdfk95 X-Gm-Gg: Acq92OEh3C/XRI1fqYPCRy2a2/0lLQt1izscByeD7gCt1X9kfSqrUDL0H+Xt3L7qPsN EeRNlKgesd8SzU5ibyXfx5IFqDXtmxrhtzHmBE5gT2Wge53jOVvzMWShOD795EEKUZ40uCi7vM3 YilM9QBGu+hq0j42yhDYUs9eGwVdJtQQsCoIsJlNcNcmsgr3l8wcrr5bGyy0OM4q4aySY6toACs YUWqTuURxS0NLTOI3B+moEf8StdqGjGIVodU41sI2PQl11Op1KesJXAFoRIqcHjEozgFaMqF1e5 GBXmvVXomm1LqjdPqJD6VndprmPCuImURohv/0HRUuFZBUr0nZap4O+jdA9aO3B5Hd+AaD0dih+ VRo3i52lnyLM50eiOrqD+IAJHQpxFRe/YgF/WnWdOkZ+EUUR1/hXNVxPgnI1ID135ewPOwUczoa w1OPMj7UANhUS2UssbizJ/zaOY9P9uwpr6KOU9LA== X-Received: by 2002:a05:600c:4e0d:b0:490:5655:8d3f with SMTP id 5b1f17b1804b1-49056558e57mr254573445e9.28.1779818226712; Tue, 26 May 2026 10:57:06 -0700 (PDT) X-Received: by 2002:a05:600c:4e0d:b0:490:5655:8d3f with SMTP id 5b1f17b1804b1-49056558e57mr254572965e9.28.1779818226327; Tue, 26 May 2026 10:57:06 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 17/19] rust/util: build QAPI types Date: Tue, 26 May 2026 19:56:16 +0200 Message-ID: <20260526175618.227743-18-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818313616158500 From: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Paolo Bonzini --- qapi/meson.build | 9 +++++++++ rust/Cargo.lock | 1 + rust/Cargo.toml | 2 +- rust/util/Cargo.toml | 1 + rust/util/meson.build | 17 +++++++++++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/qapi/meson.build b/qapi/meson.build index a46269b5a0c..a019ec19db1 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -130,3 +130,12 @@ foreach output : qapi_outputs util_ss.add(qapi_files[i]) i =3D i + 1 endforeach + +# TODO: build together with the other files, perhaps when Rust is not +# optional and/or the Rust backend is complete (currently lacking +# commands, events, modules) +qapi_rs_files =3D custom_target('QAPI Rust', + output: 'qapi-types.rs', + input: [ files('qapi-schema.json') ], + command: [ qapi_gen, '-o', 'qapi', '-b', '@INPUT0@', '-B', 'qapi.backend= .QAPIRsBackend' ], + depend_files: [ qapi_inputs, qapi_gen_depends ]) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index b9e8636b8bc..c73f037d689 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -514,6 +514,7 @@ dependencies =3D [ "glib-sys", "libc", "serde", + "serde_derive", "util-sys", ] =20 diff --git a/rust/Cargo.toml b/rust/Cargo.toml index fe491f3aba6..15296ac8636 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -20,7 +20,7 @@ anyhow =3D "~1.0" foreign =3D "~0.3.1" libc =3D "0.2.162" glib-sys =3D { version =3D "0.21.2", features =3D ["v2_66"] } -serde =3D "1.0.226" +serde =3D { version =3D "1.0.226", features =3D ["derive"] } serde_derive =3D "1.0.226" =20 [workspace.lints.rust] diff --git a/rust/util/Cargo.toml b/rust/util/Cargo.toml index 0a0400278f3..069ab167e87 100644 --- a/rust/util/Cargo.toml +++ b/rust/util/Cargo.toml @@ -18,6 +18,7 @@ foreign =3D { workspace =3D true } glib-sys =3D { workspace =3D true } libc =3D { workspace =3D true } serde =3D { workspace =3D true } +serde_derive =3D { workspace =3D true } common =3D { path =3D "../common" } util-sys =3D { path =3D "../bindings/util-sys" } =20 diff --git a/rust/util/meson.build b/rust/util/meson.build index a8d9978e1a9..3edd8245bfc 100644 --- a/rust/util/meson.build +++ b/rust/util/meson.build @@ -18,3 +18,20 @@ rust.doctest('rust-util-rs-doctests', dependencies: util_rs, suite: ['doc', 'rust'] ) + +_qapi_cfg =3D run_command(rustc_args, + '--no-strict-cfg', + '--config-headers', config_host_h, + capture: true, check: true).stdout().strip().splitlines() + +_qapi_rs =3D static_library( + 'qapi', + qapi_rs_files, + rust_args: _qapi_cfg, + override_options: ['rust_std=3D2021', 'build.rust_std=3D2021'], + rust_abi: 'rust', + link_with: [_util_rs], + dependencies: [common_rs, serde_rs], +) + +qapi_rs =3D declare_dependency(link_with: [_qapi_rs]) --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818255; cv=none; d=zohomail.com; s=zohoarc; b=lfhZbjlyg6mHK9x/FYy8ump6yazyGzVWOCYHj8EhQJuTw2CocwdJlrCMtJqRYblmSb3TL6E9CpyN952ZlfX+DhJpGRlycyKDHzoWYeHy0PIxd3+OQFHffegpVDibMuiPIZDNBeojuLKgnx7zN/XAXYnkEvXpvdf9egGJWLBGCIE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818255; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=6C9lsEi5iNLqmgqFh1Mzb9/99gwNr4jDcrF6Yon6gz4=; b=a1RjrVU8L0sCxZ1N+Y/A0zVF1rCqvMPRnDwgAIU47/XYGPbTQba18rqh9PbYev0MWgWLFr1mQj+2q9Qs1JwNioN6p058W7zxvYOT9m1IF4FkS68GQ/nJRIvulGzq9FZzE9odQRNdpAAa/3mGq7QmKf2uRUn8gPuQu2hm79tZNCI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177981825533957.74534298528397; Tue, 26 May 2026 10:57:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1o-0002Ne-2s; Tue, 26 May 2026 13:57:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1m-0002Lx-At for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:18 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1k-00087K-Hd for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:17 -0400 Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-295-0uQ73Yi3N5GPrDkKNJop-w-1; Tue, 26 May 2026 13:57:13 -0400 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-449dcfe8005so8596291f8f.3 for ; Tue, 26 May 2026 10:57:13 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6c9de2dsm35999338f8f.4.2026.05.26.10.57.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:57:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818235; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6C9lsEi5iNLqmgqFh1Mzb9/99gwNr4jDcrF6Yon6gz4=; b=FoBPA64OpvFN4GSLTAkJVkRvdfNpSU4UghDY06tqdJMd8OooN9yrId3Di6+Gbpq9w7kyOx XvdY/z8wg572qcYsfqtUHCO9QOOh4vMjgaePaBvGILkJazaiubGgdpIswBSWezlJTlYrie x7/hKSoxgaw68t0iNABwFrGONsClzro= X-MC-Unique: 0uQ73Yi3N5GPrDkKNJop-w-1 X-Mimecast-MFC-AGG-ID: 0uQ73Yi3N5GPrDkKNJop-w_1779818233 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818232; x=1780423032; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=6C9lsEi5iNLqmgqFh1Mzb9/99gwNr4jDcrF6Yon6gz4=; b=R7tPD3j5ku0wB7QWoxoMQla9TDd04dxwZscyWNixOY5gq6CMgyvUm53W158n5xtZ0v v5n2+BBVIcsokSvlt2d9swJDD1R5+hfm/tP1V6WQZxaXfx2jiyhOiUME24tlsJAummEW rzibfqvRyLcbLwd75mnhh825BqCGtArz+MPh4QrdzDjfBAzqGxoMxoFA1ncOb0iKafas YN6zM75o26W/MvwX/g46C96RsojvIXanbAKJJ1OtlZJBAYLDUQGYBtEzIPBwGAm5hQvF kAcpIuSCU4P5FjGS2xKZyNaIJwGCnjqBzFjEJxR5cZ1EpBabPsx8SbshRXcB4vAfYJ/O z6aA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818232; x=1780423032; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=6C9lsEi5iNLqmgqFh1Mzb9/99gwNr4jDcrF6Yon6gz4=; b=cJx6/9qKHOhkPTD6VT9hN1+aYFQHFP8x910AWmpmnSdOvxd99Xg0sCYAQsRJ3KuMWc s9ySwfVcxVTqt5gm/ER5gkGBf0ctRfwnNOCjwM4iDoJiLVxslKT8USsyJBrWL4G//s5i oF4OgYzRiw8ExHyJ0ZfONOBKmn0U9OEUK+Ewcrr0VBNA6/pSn9LnjXunLnNcd8MR56uw FkzWiQdr0iHio7h7X7i8JAXxIlfobJ3EaWBebChlmfWG4GqaCQL7oAiDr+dIW7OVKV1H Qg++qI4fbrqk2pdEz7yoi2utiBWDNpSULxLcN0p8ZJ3SU1tvzzqLkXVBXcQXmlMfubfs CdDA== X-Gm-Message-State: AOJu0Yx6PCTePF/29WghvDUSACuSlosNq69EWKxtIE5Ien9k5oFH8xgj 7gkTG64ivUxO7R+Og9myzjc1Ohoq+QxeZ2fDsMF1U0YdJW9lWwgWlPdoBgCyifM8zCJCwj0KM9A FBjePM2NO2XzwRyYsPKG4gcrlvFAbZ63BhQQiMjDfltEVsdJ4PYbHt5iUA+c2nYlh/rRMk4t6OB Sam6dL/kzJt3WmVSFvQw00o+hiaAWgAqc4bsjs5ZpZ X-Gm-Gg: Acq92OHFCaSm89j/6Ud/0HXpTM+no97q7ImNC3r5kueCVlLHboHzAKrO0Tfi0O2xs8F 9/TY2aFNv7Eti/cpkTd5Hl/ekc93oZekXEJvycdJFNZFnmPAaSenfzJMWMdL4uqzUks0mDdZUfQ gKYk05TuwLI1KA0g9FBbTM1naALHIJu7LRg060OFgZVVDDnHuA+NrlWimdNYK82fOhXrWu0MxKI J91GEJrZiEC6NxhiOslg+9Q5CLvKaxVKxR8H92qOE3tWjTY1FtHD8VrrDUEnXHpPrmgM9JVey6d CyOF1CfBSm/4c6PqsYx4pnT3iYFG5KIxFsDi8QY7vGhEgZchsdS+0gqUCjA7YE7UD8iqP1mvpu4 M7g8ut95H1EAfolw8E+ufxFap90fYgi9FCY91gdp2Cz51czp1q/fkXpxyy0QaqDSa3malYKDkoi kJE38ai42zsN5g6G15Jdcdm07y3jE= X-Received: by 2002:a05:6000:2888:b0:43d:d037:d59c with SMTP id ffacd0b85a97d-45eb3697a48mr34282361f8f.16.1779818232584; Tue, 26 May 2026 10:57:12 -0700 (PDT) X-Received: by 2002:a05:6000:2888:b0:43d:d037:d59c with SMTP id ffacd0b85a97d-45eb3697a48mr34282303f8f.16.1779818232079; Tue, 26 May 2026 10:57:12 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 18/19] scripts/qapi: add serde attributes Date: Tue, 26 May 2026 19:56:17 +0200 Message-ID: <20260526175618.227743-19-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818257331158500 Generate serde attributes to match the serialization format to QAPI's: - for enums, map Rust enum variants to original QAPI names - for structs, rejects JSON with extra fields and omit optional fields (as opposed to serializing them as null) - for union variants: - use tagged union format matching QAPI's discriminator, - map variant names to original QAPI names - flatten union data into parent struct - for alternates, use type-based discrimination Signed-off-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Paolo Bonzini --- scripts/qapi/rs_types.py | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/scripts/qapi/rs_types.py b/scripts/qapi/rs_types.py index 874ebdbfa41..41ed83c381d 100644 --- a/scripts/qapi/rs_types.py +++ b/scripts/qapi/rs_types.py @@ -34,6 +34,7 @@ =20 =20 objects_seen =3D set() +SERDE_SKIP_NONE =3D '#[serde(skip_serializing_if =3D "Option::is_none")]' =20 =20 def gen_rs_variants_to_tag(name: str, @@ -80,10 +81,12 @@ def gen_rs_variants(name: str, ret =3D mcgen(''' =20 %(cfg)s''', ''' -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(tag =3D "%(tag)s")] pub enum %(rs_name)sVariant {''', cfg=3Difcond.rsgen(), - rs_name=3Drs_name(name)) + rs_name=3Drs_name(name), + tag=3Dvariants.tag_member.name) =20 for var in variants.variants: type_name =3D var.type.name @@ -91,18 +94,22 @@ def gen_rs_variants(name: str, if type_name =3D=3D 'q_empty': ret +=3D mcgen(''' %(cfg)s''', ''' + #[serde(rename =3D "%(rename)s")] %(var_name)s, ''', cfg=3Dvar.ifcond.rsgen(), - var_name=3Dvar_name) + var_name=3Dvar_name, + rename=3Dvar.name) else: ret +=3D mcgen(''' %(cfg)s''', ''' + #[serde(rename =3D "%(rename)s")] %(var_name)s(%(rs_type)s), ''', cfg=3Dvar.ifcond.rsgen(), var_name=3Dvar_name, - rs_type=3Dvar.type.rs_type()) + rs_type=3Dvar.type.rs_type(), + rename=3Dvar.name) =20 ret +=3D mcgen(''' } @@ -158,9 +165,11 @@ def gen_struct_members(members: List[QAPISchemaObjectT= ypeMember], typ =3D 'Option<%s>' % typ ret.append(mcgen(''' %(cfg)s''', ''' +%(skip_if)s''', ''' pub %(rs_name)s: %(rs_type)s, ''', cfg=3Dmemb.ifcond.rsgen(), + skip_if=3DSERDE_SKIP_NONE if memb.optional else '= ', rs_type=3Dtyp, rs_name=3Drs_name(camel_to_lower(memb.name)))) return '\n'.join(ret) @@ -181,17 +190,23 @@ def gen_rs_object(name: str, ret =3D '' objects_seen.add(name) =20 + serde_deny_unknown_fields =3D "#[serde(deny_unknown_fields)]" if variants: ret +=3D gen_rs_variants(name, ifcond, variants) + # we can't use because of the flatten unions + # serde FlatMapAccess should consume the fields? + serde_deny_unknown_fields =3D "" =20 ret +=3D mcgen(''' =20 %(cfg)s''', ''' -#[derive(Clone, Debug, PartialEq)]''', ''' +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]''', ''' +%(serde_deny_unknown_fields)s''', ''' pub struct %(rs_name)s { ''', cfg=3Difcond.rsgen(), - rs_name=3Drs_name(name)) + rs_name=3Drs_name(name), + serde_deny_unknown_fields=3Dserde_deny_unknown_fields) =20 if base: if not base.is_implicit(): @@ -213,6 +228,7 @@ def gen_rs_object(name: str, =20 if variants: ret +=3D mcgen(''' + #[serde(flatten)] pub u: %(rs_type)sVariant, ''', rs_type=3Drs_name(name)) ret +=3D mcgen(''' @@ -227,7 +243,7 @@ def gen_rs_enum(name: str, ret =3D mcgen(''' =20 %(cfg)s''', ''' -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] ''', cfg=3Difcond.rsgen()) =20 @@ -242,10 +258,12 @@ def gen_rs_enum(name: str, for member in members: ret +=3D mcgen(''' %(cfg)s''', ''' + #[serde(rename =3D "%(member_name)s")] %(c_enum)s, ''', cfg=3Dmember.ifcond.rsgen(), - c_enum=3Drs_name(camel_to_upper(member.name))) + c_enum=3Drs_name(camel_to_upper(member.name)), + member_name=3Dmember.name) ret +=3D '''} =20 ''' @@ -279,7 +297,8 @@ def gen_rs_alternate(name: str, =20 ret +=3D mcgen(''' %(cfg)s''', ''' -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] pub enum %(rs_name)s { ''', cfg=3Difcond.rsgen(), @@ -329,6 +348,8 @@ def visit_begin(self, schema: QAPISchema) -> None: // that *could* be Eq too. #![allow(clippy::derive_partial_eq_without_eq)] =20 +use serde_derive::{Serialize, Deserialize}; + use util::qobject::QObject; ''')) =20 --=20 2.54.0 From nobody Sat May 30 17:44:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1779818325; cv=none; d=zohomail.com; s=zohoarc; b=bGY8T+wJx/KTCtkrKJ9OcEEPQp3+knYRhUCofmdrsSoDQkYa7QIRhdKzt+UleU7yGsz38ICsz/A3QmEiQZYDiPCNDd6WwDqFYB8nwr+zjjzZeFCXiIxc1UsdOmNEo0SkpFQ7p1ajnY14DUpjLAU1Xe/oSI2AxoigPfElLx+Hdvk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779818325; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=XKvlfyawLfccqJb9rJlQW6VYUC+q6lpyZRnjc/NQN9M=; b=Ch8EY4Bh6dF6Hz9H1G87RNCd5W2/KC+aXxOydI8RFzWCogc0+JMlBj+DsUIMEWiTTtZl8Xd26zjIUNfsXcRsJal4YEDmaHjV8IxHJ6WX5XGN9LvYCDbA1tLlwh12U4eVH+D43xrLOFQVBS8yF+wBj6Tdvkh3HlOdyA4ImmzBi7I= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779818325637650.1150898222431; Tue, 26 May 2026 10:58:45 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wRw1q-0002OU-Mc; Tue, 26 May 2026 13:57:22 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1o-0002Nk-Iv for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:20 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wRw1m-00087V-2b for qemu-devel@nongnu.org; Tue, 26 May 2026 13:57:20 -0400 Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-564-q3yY1auCMW22ufgTOwr02g-1; Tue, 26 May 2026 13:57:15 -0400 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-43fe791a398so8257685f8f.0 for ; Tue, 26 May 2026 10:57:15 -0700 (PDT) Received: from [192.168.10.48] ([151.49.251.208]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6ccd211sm47162302f8f.10.2026.05.26.10.57.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 10:57:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779818237; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XKvlfyawLfccqJb9rJlQW6VYUC+q6lpyZRnjc/NQN9M=; b=DCSiFG1FeA1uZyPpC26tWHD9FX8vBErc/Jh3rJegwG0WkP0fUraEFezu6PgxlHxaUvARzv udcceQw+cbSRmsL4X0Z3oslrs9PfEwzJ5jVxvPvoyusKdb5Q/eOZdCFT7G8PcCo+w070Jv ymfflNGmKkKg4Hu2CNNPv5fNJddRS7s= X-MC-Unique: q3yY1auCMW22ufgTOwr02g-1 X-Mimecast-MFC-AGG-ID: q3yY1auCMW22ufgTOwr02g_1779818234 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1779818234; x=1780423034; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=XKvlfyawLfccqJb9rJlQW6VYUC+q6lpyZRnjc/NQN9M=; b=cfl70Q1SYyYPu9NpE7JZKKtRSDB/vM75CBP+kXImTENgfNiwCAVg5s2qPp6kj1NnMp 7znk7E0GaAkCRxGN75jcLwt7+GiW4q5RX57et7Dw+yi/7WpyzsT29ANZzF5q4JA3mLLn derHh4zdBBosSRTOSpbw2req+J71HENRsT77JQ1HsjrkhhbyBwkZOtJiOSjRPOtzQ5fX Hu+hPppa1H4LVhHpynJMewk7ZuafqqA1TUUH2Sdqqeu7XasiHFnylZpjeR0Tfj1RBcTS 87/AmBhm1Hmuzy1K9mJ4J1g2vs8an6OoNOvMxYNHvvzbUMAkDdYZ/w93SA0+bGsFxc+G 7GZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779818234; x=1780423034; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=XKvlfyawLfccqJb9rJlQW6VYUC+q6lpyZRnjc/NQN9M=; b=PXKNQp4sf/IsKICRjbuvYB9+YCBbWqbneNOB3cjxT8HPQ2E5bsK4hOljvtl/GNg1BQ knWkfUPa88C2UqUazlSgNCcT5X51J+AydQxE/24yq7d69F6BfQtIb8HP63C8P4EQExzW uRSdWibMhgQNfFw9ZP02fyruGhNIDaEqrexj4tpKuYZ+0D3QdGXFe3N3+f98OSwH4XGf gYJZyPUFA6RvHFUIeGo/5NL9bt76YnuxukXGFXN8QMvxl0Awc9/n3IEYh/Q8ad39NkA4 RcpMBCvHJLy7dJXrlBhA/pBqfewNcP603ZfpalzN6ZaXt4VSfFaEC0nSqxLN5CBdORNx lDag== X-Gm-Message-State: AOJu0YwBzo/kzfD3Y1ZKU/9AF0iSU/YTQN2f5TNHWOuWzWlAVhtFrSkC CesvaQjGiD5207YzTzlCOG2AODOWyQwNv0E1w2xpOPt0Xlroj9mmiCEWIhQz9kKNnH6TkrbxRFv ug5eMYkPmlCmejGZB/u+rzs+eaRt9YuLtvv0IaWHHqs1ldU39UrRg4SxqNzNBsQNf/GMAXrbyrF Fp7xhgkF1WW14Yr/U1HMREc0kYJ6CMhhngrclQbRr5 X-Gm-Gg: Acq92OG6sX7HCvDYsqCDCHchtRq/gMPvR5DdetUmLcXg/1I/ye07GtkM+kJj4CaPTYS hDhv2lnOveR9ts4bWN6PGnnuRvT+KaCwGnhFOdVr0i8M/ZrUvz5QcRVtkVDwjWiSoZMSIqp7dSf k7B+Lkc2RRtU2bdD0tpBep7Ug/ZAGJOsy8u2FmiuQWpgY36GlcLBBBeKvsldlKIBhp2t4SrGaZ8 I3PCyteYuk0jVO5N76MMK9pjlGg8NM0UHaNXCE/Dbh9N9SY8vOrvJXAfcL6j8BaXqwFTYXfQdVI +IVuIsfG+BJLeE+u1S7ZQ+fBf9JKZd6mZqkYqEF+Sgkd1x7KyGWrl2kZAOsOlWB9Rx2MoxzNrC8 HtVgCd8oL4ddSQZvbEA3P1Ro5Dcyr4I0P0yCmr2xsLglIJ61LA6//aHoKmj9MMI3v6nHI6fz6x7 xJWHAkczxx5h2e0Nl6MBcJUSF/hno= X-Received: by 2002:a05:6000:260e:b0:45e:a0ab:8bcb with SMTP id ffacd0b85a97d-45eb3696a9fmr31481335f8f.15.1779818234279; Tue, 26 May 2026 10:57:14 -0700 (PDT) X-Received: by 2002:a05:6000:260e:b0:45e:a0ab:8bcb with SMTP id ffacd0b85a97d-45eb3696a9fmr31481267f8f.15.1779818233774; Tue, 26 May 2026 10:57:13 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, armbru@redhat.com, marcandre.lureau@redhat.com Subject: [PATCH v3 19/19] rust/tests: QAPI integration tests Date: Tue, 26 May 2026 19:56:18 +0200 Message-ID: <20260526175618.227743-20-pbonzini@redhat.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260526175618.227743-1-pbonzini@redhat.com> References: <20260526175618.227743-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1779818327417154100 From: Marc-Andr=C3=A9 Lureau Signed-off-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Paolo Bonzini --- rust/tests/meson.build | 21 +- rust/tests/tests/integration.rs | 2 + rust/tests/tests/qapi.rs | 444 ++++++++++++++++++++++++++++++++ 3 files changed, 464 insertions(+), 3 deletions(-) create mode 100644 rust/tests/tests/integration.rs create mode 100644 rust/tests/tests/qapi.rs diff --git a/rust/tests/meson.build b/rust/tests/meson.build index 3c5020490b0..d781b52bd78 100644 --- a/rust/tests/meson.build +++ b/rust/tests/meson.build @@ -1,10 +1,25 @@ +test_qapi_rs_files =3D custom_target('QAPI Rust', + output: 'test-qapi-types.rs', + input: [ files(meson.project_source_root() + '/tests/qapi-schema/qapi-sc= hema-test.json') ], + command: [ qapi_gen, '-o', meson.current_build_dir(), '-b', '@INPUT0@', = '-B', 'qapi.backend.QAPIRsBackend', '-p', 'test-' ], + depend_files: [ qapi_inputs, qapi_gen_depends ]) + +_test_qapi_rs =3D static_library( + 'test_qapi', + test_qapi_rs_files, + override_options: ['rust_std=3D2021', 'build.rust_std=3D2021'], + rust_abi: 'rust', + dependencies: [common_rs, util_rs, serde_rs, serde_derive_rs]) + +test_qapi_rs =3D declare_dependency(link_with: [_test_qapi_rs]) + test('rust-integration', executable( 'rust-integration', - files('tests/vmstate_tests.rs'), - rust_args: ['--test'], + files('tests/integration.rs'), + rust_args: ['--test'] + _qapi_cfg, install: false, - dependencies: [bql_rs, common_rs, util_rs, migration_rs, qom_rs]), + dependencies: [bql_rs, common_rs, util_rs, migration_rs, qom_rs, q= api_rs, test_qapi_rs]), args: [ '--test', '--test-threads', '1', '--format', 'pretty', diff --git a/rust/tests/tests/integration.rs b/rust/tests/tests/integration= .rs new file mode 100644 index 00000000000..ebc17cb5550 --- /dev/null +++ b/rust/tests/tests/integration.rs @@ -0,0 +1,2 @@ +mod qapi; +mod vmstate_tests; diff --git a/rust/tests/tests/qapi.rs b/rust/tests/tests/qapi.rs new file mode 100644 index 00000000000..f8a585e5802 --- /dev/null +++ b/rust/tests/tests/qapi.rs @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#![allow(unexpected_cfgs)] +#![allow(clippy::shadow_unrelated)] + +use util::qobject::{from_qobject, to_qobject, QObject}; + +#[test] +fn test_char() { + let json =3D "\"v\""; + let qo =3D QObject::from_json(json).unwrap(); + let c: char =3D from_qobject(qo).unwrap(); + assert_eq!(c, 'v'); + assert_eq!(to_qobject(c).unwrap().to_json(), json); + + let json =3D "'va'"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); +} + +#[test] +fn test_enum() { + let json =3D "\"value1\""; + let qo =3D QObject::from_json(json).unwrap(); + let e: test_qapi::EnumOne =3D from_qobject(qo).unwrap(); + assert_eq!(e, test_qapi::EnumOne::VALUE1); + assert_eq!(to_qobject(e).unwrap().to_json(), json); +} + +#[test] +fn test_struct() { + let expected =3D test_qapi::TestStruct { + integer: -42, + boolean: true, + string: "foo".into(), + }; + let json =3D "{\"integer\": -42, \"boolean\": true, \"string\": \"foo\= "}"; + let qo =3D QObject::from_json(json).unwrap(); + let ts: test_qapi::TestStruct =3D from_qobject(qo).unwrap(); + assert_eq!(ts, expected); + assert_eq!(to_qobject(ts).unwrap().to_json(), json); +} + +#[test] +fn test_struct_nested() { + let expected =3D test_qapi::UserDefTwo { + string0: "string0".into(), + dict1: test_qapi::UserDefTwoDict { + string1: "string1".into(), + dict2: test_qapi::UserDefTwoDictDict { + userdef: test_qapi::UserDefOne { + integer: 42, + string: "string".into(), + enum1: None, + }, + string: "string2".into(), + }, + dict3: None, + }, + }; + let json =3D "{\"string0\": \"string0\", \"dict1\": {\"dict2\": {\"str= ing\": \"string2\", \ + \"userdef\": {\"integer\": 42, \"string\": \"string\"}}, \= "string1\": \ + \"string1\"}}"; + let qo =3D QObject::from_json(json).unwrap(); + let udt: test_qapi::UserDefTwo =3D from_qobject(qo).unwrap(); + assert_eq!(udt, expected); + assert_eq!(to_qobject(udt).unwrap().to_json(), json); +} + +#[test] +fn test_list() { + let expected =3D [ + test_qapi::UserDefOne { + integer: 42, + string: "string0".into(), + enum1: None, + }, + test_qapi::UserDefOne { + integer: 43, + string: "string1".into(), + enum1: None, + }, + test_qapi::UserDefOne { + integer: 44, + string: "string2".into(), + enum1: None, + }, + ]; + let json =3D "[{\"integer\": 42, \"string\": \"string0\"}, {\"integer\= ": 43, \"string\": \ + \"string1\"}, {\"integer\": 44, \"string\": \"string2\"}]"; + let qo =3D QObject::from_json(json).unwrap(); + let ud_list: Vec =3D from_qobject(qo).unwrap(); + assert_eq!(ud_list, expected); + assert_eq!(to_qobject(ud_list).unwrap().to_json(), json); +} + +#[test] +fn test_flat_union() { + let expected =3D test_qapi::UserDefFlatUnion { + integer: 41, + string: "str".into(), + u: test_qapi::UserDefFlatUnionVariant::Value1(test_qapi::UserDefA { + boolean: true, + a_b: None, + }), + }; + let json =3D "{\"integer\": 41, \"boolean\": true, \"enum1\": \"value1= \", \"string\": \"str\"}"; + let qo =3D QObject::from_json(json).unwrap(); + let ud_fu: test_qapi::UserDefFlatUnion =3D from_qobject(qo).unwrap(); + assert_eq!(ud_fu, expected); + assert_eq!(to_qobject(ud_fu).unwrap().to_json(), json); +} + +#[test] +fn test_union_in_union() { + let expected =3D test_qapi::TestUnionInUnion { + u: test_qapi::TestUnionInUnionVariant::ValueA(test_qapi::TestUnion= TypeA { + u: test_qapi::TestUnionTypeAVariant::ValueA1(test_qapi::TestUn= ionTypeA1 { + integer: 2, + name: "fish".into(), + }), + }), + }; + let json =3D + "{\"name\": \"fish\", \"integer\": 2, \"type-a\": \"value-a1\", \"= type\": \"value-a\"}"; + let qo =3D QObject::from_json(json).unwrap(); + let uu: test_qapi::TestUnionInUnion =3D from_qobject(qo).unwrap(); + assert_eq!(uu, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::TestUnionInUnion { + u: test_qapi::TestUnionInUnionVariant::ValueA(test_qapi::TestUnion= TypeA { + u: test_qapi::TestUnionTypeAVariant::ValueA2(test_qapi::TestUn= ionTypeA2 { + integer: 1729, + size: 87539319, + }), + }), + }; + let json =3D + "{\"integer\": 1729, \"type-a\": \"value-a2\", \"size\": 87539319,= \"type\": \"value-a\"}"; + let qo =3D QObject::from_json(json).unwrap(); + let uu: test_qapi::TestUnionInUnion =3D from_qobject(qo).unwrap(); + assert_eq!(uu, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::TestUnionInUnion { + u: test_qapi::TestUnionInUnionVariant::ValueB(test_qapi::TestUnion= TypeB { + integer: 1729, + onoff: true, + }), + }; + let json =3D "{\"integer\": 1729, \"onoff\": true, \"type\": \"value-b= \"}"; + let qo =3D QObject::from_json(json).unwrap(); + let uu: test_qapi::TestUnionInUnion =3D from_qobject(qo).unwrap(); + assert_eq!(uu, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); +} + +#[test] +fn test_alternate() { + let expected =3D test_qapi::UserDefAlternate::I(42); + let json =3D "42"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::UserDefAlternate =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::UserDefAlternate::E(test_qapi::EnumOne::VA= LUE1); + let json =3D "\"value1\""; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::UserDefAlternate =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::UserDefAlternate::N(()); + let json =3D "null"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::UserDefAlternate =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::UserDefAlternate::Udfu(test_qapi::UserDefF= latUnion { + integer: 42, + string: "str".to_string(), + u: test_qapi::UserDefFlatUnionVariant::Value1(test_qapi::UserDefA { + boolean: true, + a_b: None, + }), + }); + let json =3D "{\"integer\": 42, \"boolean\": true, \"enum1\": \"value1= \", \"string\": \"str\"}"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::UserDefAlternate =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::WrapAlternate { + alt: test_qapi::UserDefAlternate::I(42), + }; + let json =3D "{\"alt\": 42}"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::WrapAlternate =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::WrapAlternate { + alt: test_qapi::UserDefAlternate::E(test_qapi::EnumOne::VALUE1), + }; + let json =3D "{\"alt\": \"value1\"}"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::WrapAlternate =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::WrapAlternate { + alt: test_qapi::UserDefAlternate::Udfu(test_qapi::UserDefFlatUnion= { + integer: 1, + string: "str".to_string(), + u: test_qapi::UserDefFlatUnionVariant::Value1(test_qapi::UserD= efA { + boolean: true, + a_b: None, + }), + }), + }; + let json =3D "{\"alt\": {\"integer\": 1, \"boolean\": true, \"enum1\":= \"value1\", \"string\": \ + \"str\"}}"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::WrapAlternate =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); +} + +#[test] +fn test_alternate_number() { + let expected =3D test_qapi::AltEnumNum::N(42.0); + let json =3D "42"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::AltEnumNum =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::AltNumEnum::N(42.0); + let json =3D "42"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::AltNumEnum =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::AltEnumInt::I(42); + let json =3D "42"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::AltEnumInt =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::AltListInt::I(42); + let json =3D "42"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::AltListInt =3D from_qobject(qo).unwrap(); + assert_eq!(&uda, &expected); + assert_eq!(to_qobject(&expected).unwrap().to_json(), json); + + // double + let json =3D "42.5"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); + + let expected =3D test_qapi::AltEnumNum::N(42.5); + let json =3D "42.5"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::AltEnumNum =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let expected =3D test_qapi::AltNumEnum::N(42.5); + let json =3D "42.5"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::AltNumEnum =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); + + let json =3D "42.5"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); +} + +#[test] +fn test_alternate_list() { + let expected =3D test_qapi::AltListInt::L(vec![42, 43, 44]); + let json =3D "[42, 43, 44]"; + let qo =3D QObject::from_json(json).unwrap(); + let uda: test_qapi::AltListInt =3D from_qobject(qo).unwrap(); + assert_eq!(uda, expected); + assert_eq!(to_qobject(expected).unwrap().to_json(), json); +} + +#[test] +fn test_errors() { + let json =3D "{ 'integer': false, 'boolean': 'foo', 'string': -42 }"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); + + let json =3D "[ '1', '2', false, '3' ]"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::>(qo).unwrap_err(); + + let json =3D "{ 'str': 'hi' }"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); + + let json =3D "{}"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); +} + +#[test] +fn test_wrong_type() { + let json =3D "[]"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); + + let json =3D "{}"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::>(qo).unwrap_err(); + + let json =3D "1"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); + + let json =3D "{}"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); + + let json =3D "1"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::>(qo).unwrap_err(); + + let json =3D "[]"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); +} + +#[test] +fn test_fail_struct() { + let json =3D "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'ext= ra': 42 }"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); +} + +#[test] +fn test_fail_struct_nested() { + let json =3D "{ 'string0': 'string0', 'dict1': { 'string1': 'string1',= 'dict2': { 'userdef1': { \ + 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo= ':'bar'}] }, 'string2': \ + 'string2'}}}"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::(qo).unwrap_err(); +} + +#[test] +fn test_fail_struct_in_list() { + let json =3D "[ { 'string': 'string0', 'integer': 42 }, { 'string': 's= tring1', 'integer': 43 }, \ + { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::>(qo).unwrap_err(); +} + +#[test] +fn test_fail_union_flat() { + let json =3D "{ 'enum1': 'value2', 'string': 'c', 'integer': 41, 'bool= ean': true }"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::>(qo).unwrap_err(); +} + +#[test] +fn test_fail_union_flat_no_discrim() { + // test situation where discriminator field ('enum1' here) is missing + let json =3D "{ 'integer': 42, 'string': 'c', 'string1': 'd', 'string2= ': 'e' }"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::>(qo).unwrap_err(); +} + +#[test] +fn test_fail_alternate() { + let json =3D "3.14"; + let qo =3D QObject::from_json(json).unwrap(); + from_qobject::>(qo).unwrap_err(); +} + +#[test] +fn test_qapi() { + let expected =3D qapi::InetSocketAddress { + host: "host-val".to_string(), + port: "port-val".to_string(), + numeric: None, + to: None, + ipv4: None, + ipv6: None, + keep_alive: None, + #[cfg(HAVE_TCP_KEEPCNT)] + keep_alive_count: None, + #[cfg(HAVE_TCP_KEEPIDLE)] + keep_alive_idle: Some(42), + #[cfg(HAVE_TCP_KEEPINTVL)] + keep_alive_interval: None, + #[cfg(HAVE_IPPROTO_MPTCP)] + mptcp: None, + }; + + let qsa =3D to_qobject(&expected).unwrap(); + let json =3D qsa.to_json(); + assert_eq!( + json, + "{\"port\": \"port-val\", \"keep_alive_idle\": 42, \"host\": \"hos= t-val\"}" + ); + let sa: qapi::InetSocketAddress =3D from_qobject(qsa).unwrap(); + assert_eq!(sa, expected); + + let expected =3D qapi::SocketAddressVariant::Inet(expected); + let qsav =3D to_qobject(&expected).unwrap(); + let json =3D qsav.to_json(); + assert_eq!( + json, + "{\"port\": \"port-val\", \"keep_alive_idle\": 42, \"host\": \"hos= t-val\", \"type\": \ + \"inet\"}" + ); + let sav: qapi::SocketAddressVariant =3D from_qobject(qsav).unwrap(); + assert_eq!(sav, expected); + + let expected =3D qapi::Qcow2BitmapInfo { + name: "name-val".to_string(), + granularity: 4096, + flags: vec![ + qapi::Qcow2BitmapInfoFlags::IN_USE, + qapi::Qcow2BitmapInfoFlags::AUTO, + ], + }; + let qbi =3D to_qobject(&expected).unwrap(); + let json =3D qbi.to_json(); + assert_eq!( + json, + "{\"flags\": [\"in-use\", \"auto\"], \"name\": \"name-val\", \"gra= nularity\": 4096}" + ); + let bi: qapi::Qcow2BitmapInfo =3D from_qobject(qbi).unwrap(); + assert_eq!(bi, expected); +} --=20 2.54.0