On Wed, Jun 11, 2025 at 9:52 AM Zhao Liu <zhao1....@intel.com> wrote: > As patch 3 did, qapi will generate Rust types: > > - char* is mapped to String, scalars to there corresponding Rust types > - enums are simply aliased from FFI > - has_foo/foo members are mapped to Option<T> > - lists are represented as Vec<T>
Yep, so far so good. > - structures have Rust versions, with To/From FFI conversions The conversion part is not included in this minimal series. The raw structure (the `type Foreign` as you point out) could be generated by either bindgen or qapi-gen. Marc-André chose the latter for his old prototype, I'm ambivalent. > It seems we still need some raw bindings (generated by bindgen) as the > `type Foreign`, and then implement Foreign traits for the Rust > structures generated by this patch. Yes. If using serde the implementation of the traits is very small, and basically the same for all types. If not using serde, it would need some (or most) of the infrastructure in Marc-André's original series. > For this example, UefiVariable is generated by qapi (patch 3) and > bindings::UefiVariable is generated by bindgen. Ah! I feel I'm wrong, > could you please correct me? You're not wrong. :) Paolo > On Thu, Jun 05, 2025 at 12:11:21PM +0200, Paolo Bonzini wrote: > > Date: Thu, 5 Jun 2025 12:11:21 +0200 > > From: Paolo Bonzini <pbonz...@redhat.com> > > Subject: [PATCH preview 0/3] reviving minimal QAPI generation from 2021 > > X-Mailer: git-send-email 2.49.0 > > > > This is just an extremely minimal extraction from the patches at > > https://patchew.org/QEMU/20210907121943.3498701-1-marcandre.lur...@redhat.com/, > > limited to generating structs and enums from the QAPI schema. > > It does not include them in any crate and does not compile them. > > > > While I'm not going to work on this, I was curious how much work it > > was to produce *some* kind of Rust QAPI struct, which could be a first > > step towards using serde as an interface to C visitors, like this: > > > > trait QapiType: FreeForeign { > > unsafe fn visit(v: bindings::Visitor, name: *const c_char, obj: *mut > > <Self as FreeForeign>::Foreign, errp: *mut *mut bindings::Error); > > } > > > > fn to_c<T: QapiType>(obj: &T) -> *mut <T as FreeForeign>::Foreign { > > let mut ptr = libc::calloc(...); > > let mut ser = QapiSerializer::<T>::new(ptr); > > obj.serialize(&mut ser).unwrap(); > > ptr.cast() > > } > > > > unsafe fn from_c<T: QapiType>(obj: *const <T as FreeForeign>::Foreign) -> T > > { > > let mut de = QapiDeserializer::new(T::visit, obj as *const c_void); > > let value = de::Deserialize::deserialize(&mut de).unwrap(); > > de.end().unwrap(); > > value > > } > > > > /* Generated code below: */ > > > > impl QapiType for UefiVariable { > > unsafe fn visit(v: bindings::Visitor, name: *const c_char, obj: *mut > > bindings::UefiVariable, errp: *mut *mut bindings::Error) { > > unsafe extern "C" visit_type_UefiVariable(v: bindings::Visitor, > > name: *const c_char, obj: *mut bindings::UefiVariable, errp: *mut *mut > > bindings::Error) { > > unsafe { visit_type_UefiVariable(v, name, obj, errp); } > > } > > } > > > > impl FreeForeign for UefiVariable { > > type Foreign = bindings::UefiVariable; > > unsafe fn free_foreign(p: *mut bindings::UefiVariable) { > > unsafe extern "C" qapi_free_UefiVariable(p: *mut > > bindings::UefiVariable); > > unsafe { qapi_free_UefiVariable(p); } > > } > > } > > > > impl CloneToForeign for UefiVariable { > > fn clone_to_foreign(&self) -> OwnedPointer<Self> { > > OwnedPointer::new(qapi::to_c(self)) > > } > > } > > > > impl FromForeign for UefiVariable { > > unsafe fn cloned_from_foreign(obj: *const bindings::UefiVariable) -> > > Self { > > qapi::from_c(obj) > > } > > }