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_DumpGuestMemoryFormat(v: 
bindings::Visitor, name: *const c_char, obj: *mut bindings::UefiVariable, errp: 
*mut *mut bindings::Error) {
        unsafe { visit_type_DumpGuestMemoryFormat(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)
    }
}

The FFI types could be generated by qapi-gen, as in Marc-André's
proposal, or from bindgen.

I am not sure what approach is better---whether to use serde or to
automatically generate the marshaling and unmarshaling code; and whether
to use bindgen or generate C-compatible FFI types---but it made sense,
from the point of view of extracting "some" code from Marc-André's
proof of concept and enticing other people, :) to start from high-level
types.

Paolo

Marc-André Lureau (2):
  scripts/qapi: add QAPISchemaIfCond.rsgen()
  scripts/qapi: generate high-level Rust bindings

Paolo Bonzini (1):
  rust: make TryFrom macro more resilient

 meson.build                     |   4 +-
 rust/qemu-api-macros/src/lib.rs |   7 +-
 scripts/qapi/backend.py         |   4 +-
 scripts/qapi/common.py          |  16 ++
 scripts/qapi/main.py            |   4 +-
 scripts/qapi/rs.py              | 183 ++++++++++++++++++
 scripts/qapi/rs_types.py        | 320 ++++++++++++++++++++++++++++++++
 scripts/qapi/schema.py          |   4 +
 8 files changed, 535 insertions(+), 7 deletions(-)
 create mode 100644 scripts/qapi/rs.py
 create mode 100644 scripts/qapi/rs_types.py

-- 
2.49.0


Reply via email to