All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Marc-André Lureau" <marcandre.lureau@gmail.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Daniel P. Berrange" <berrange@redhat.com>,
	QEMU <qemu-devel@nongnu.org>,
	Stefan Hajnoczi <stefanha@redhat.com>,
	Markus Armbruster <armbru@redhat.com>
Subject: Re: [RFC v3 12/32] rust: provide a common crate for QEMU
Date: Tue, 14 Sep 2021 15:34:06 +0400	[thread overview]
Message-ID: <CAJ+F1CK4s-D+Rwz6EG9+mUxb8EUJJuphF5Ox+gtsEq+CNL7zAQ@mail.gmail.com> (raw)
In-Reply-To: <d84f2827-3dbf-abc1-0ce3-596f0c568cf3@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 7936 bytes --]

Hi Paolo

On Mon, Sep 13, 2021 at 9:18 PM Paolo Bonzini <pbonzini@redhat.com> wrote:

> On 07/09/21 14:19, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau<marcandre.lureau@redhat.com>
> >
> > This crates provides common bindings and facilities for QEMU C API
> > shared by various projects.
> >
> > Most importantly, it defines the conversion traits used to convert from
> > C to Rust types. Those traits are largely adapted from glib-rs, since
> > those have proved to be very flexible, and should guide us to bind
> > further QEMU types such as QOM. If glib-rs becomes a dependency, we
> > should consider adopting glib translate traits. For QAPI, we need a
> > smaller subset.
> >
> > Cargo.lock is checked-in, as QEMU produces end-of-chain binaries, and it
> > is desirable to track the exact set of packages that are involved in
> > managed builds.
> >
> > Signed-off-by: Marc-André Lureau<marcandre.lureau@redhat.com>
>
> As in my previous review, the main issue I have here is with the
> complexity of this code.
>
> I understand that this has to be manually written, but right now I find
> it really hard to understand what is going on here.  The patch needs to
> be expanded in several parts:
>
> 1) generic traits (including implementations for Option/Box)
>
> 2) implementation of the generic traits
>
> 3) io/nix errors
>
> and these parts should be moved around to the place where they become
> necessary.
>
>
The common crate can be split in many pieces. It is easier to have it as a
single commit during PoC/RFC (the series is already large enough).

Is it really valuable to introduce a new crate/library piece by piece?
Instead, better documentation and tests are more valuable imho. But I will
certainly split it and clean it more as we iterate.


> Also regarding the code itself:
>
> 1) Stash should not be a tuple.  Accesses to it should use standard Rust
> methods, such as borrow()/borrow_mut(), and it should also support
> standard Rust idioms such as map():
>
>

I thought we already discussed that. The stash is an implementation detail
to handle FFI resource release. The only thing the user should care about
the stash is the pointer, which is shortly retrieved with ".0" (cannot be
more succinct).

Ideally, we would like to provide "foo.to_qemu_none()", but to keep the
associated resource allocated, the shortest we can offer is
"foo.to_qemu_none().0". Using "as_ptr()" instead would not only be longer
to type but possibly misleading: there is nothing else you should do with
the stash, no other method should exist.

I don't understand what "map()" would provide here either. The storage part
of the stash is an internal detail (the FFI data), not meant to be
manipulated at all (it would invalidate the stash pointer).



> pub struct BorrowedMutPointer<'a, P, T: 'a> {
>      native: *mut P,
>      storage: T,
>      _marker: PhantomData<&'a P>,
> }
>
> #[allow(dead_code)]
> impl<'a, P: Copy, T: 'a> BorrowedMutPointer<'a, P, T> {
>      fn as_ptr(&self) -> *const P {
>          self.native
>      }
>
>      fn as_mut_ptr(&mut self) -> *mut P {
>          self.native
>      }
>
>      fn map<U: 'a, F: FnOnce(T) -> U>(self, f: F) ->
> BorrowedMutPointer<'a, P, U> {
>          BorrowedMutPointer {
>              native: self.native,
>              storage: f(self.storage),
>              _marker: PhantomData,
>          }
>      }
> }
>
> impl<'a, P, T> Borrow<T> for BorrowedMutPointer<'a, P, T> {
>      fn borrow(&self) -> &T {
>          &self.storage
>      }
> }
>
> impl<'a, P, T> BorrowMut<T> for BorrowedMutPointer<'a, P, T> {
>      fn borrow_mut(&mut self) -> &mut T {
>          &mut self.storage
>      }
> }
>
> 2) Does ToQemuPtr need to allow multiple implementations?  Can the type
> parameter in ToQemuPtr<'a, P> be an associated type (for example
> "Native")?  Type parameters really add a lot of complexity.
>
>

ToQemuPtr is a trait, implemented for the various Rust types that we can
translate to FFI pointers.

For example:

impl<'a> ToQemuPtr<'a, *mut c_char> for String {
    type Storage = CString;
...
}

The pointer type parameter is to return the correct pointer. It is not
necessary to specify it as a user, since Rust infers it from the expected
type.


> 3) I would rather not have "qemu" in the names.  The Rust parts *are*
> QEMU.  So "foreign" or "c" would be better.
>


That's kind of cosmetic.

The main reason for "qemu" in the name is to avoid potential clashes with
other methods and traits.

Also "to_none" could associate in the reader's mind (wrongly) with the
ubiquitous Option::None.

But yes, we could drop "qemu" here.


>
> 4) full/none is still really confusing to me.  I have finally understood
> that it's because the pair that borrows is from_qemu_full/to_qemu_none,
> and the pair that copies is from_qemu_none/to_qemu_full.  I'd really
> like to use names following the Rust naming conventions.  A possible
> improvement of my proposal from the previous review:
>
>

"full" and "none" are inherited from the glib-introspection ownership
transfer annotations.

We discussed and weighed pros and cons last year. I haven't yet found or
agreed on better options. And you can be certain that the glib-rs folks
have already pondered a lot about the naming and design. And, I don't like
to reinvent what others have done (creating various limitations and
incompatibilities). Following the glib traits brings a lot of experience
and could help us reuse glib-rs crates more easily (because they would use
the same design), but also to port and interoperate. Imagine we need to
bind GHashTable<char *, QapiFoo> someday, we will be in a better position
if we have translation traits that follow glib-rs already.

The Rust conventions can be inferred from CString/CStr design and methods,
but they have to be adjusted, because they don't solve the same constraints
(no ownership transfer, and CString/CStr intermediary representations).

They are "CStr::from_ptr(*const)" and "CString::as_ptr(&self) -> *const".


- from_qemu_full -> from_foreign (or from_c, same below)
>                      + possibly a dual method into_native or into_rust
>
>
There is no standard naming for such FFI pointer ownership transfer. Rust
doesn't know how to release FFI resources, in general.

from_raw(*mut) is the closest, but "raw" is reserved for Rust data pointer
types, not FFI (except for slices, probably because the linear layout is
the same as FFI)

We can consider "from_mut_ptr(*mut)", but this doesn't convey the ownership
transfer as explicitly.


> - from_qemu_none -> cloned_from_foreign
>

You are being creative! This is like "CStr::from_ptr", except we go
directly to higher Rust types.


> - to_qemu_none -> as_foreign or as_foreign_mut
>
>
Similarity with "CString::as_ptr", except that it handles the temporary
stash (CString is the internal storage for String), so we use the
"to_qemu_none().0" described earler.

If we follow your considerations it could be "to_stash().as_ptr()", which
is less user friendly, exposes more internal details, etc.


> - to_qemu_full -> clone_to_foreign
>


There is no equivalent in Rust standard. An implementation may want to
store in an existing location, or allocated in different ways etc.

Closest would be to_ptr()

In summary:

from_qemu_full()  vs  from_mut_ptr()
from_qemu_none()      from_ptr()
to_qemu_full()        to_ptr()
to_qemu_none()        to_stash().as_ptr()

I argue there is more consistency and readability by following the glib-rs
traits and method names (among other advantages by staying close to glib-rs
design for the future).


>
> I will see if I have some time to do some of this work.
>
>
thanks


-- 
Marc-André Lureau

[-- Attachment #2: Type: text/html, Size: 11010 bytes --]

  reply	other threads:[~2021-09-14 11:35 UTC|newest]

Thread overview: 74+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-07 12:19 [RFC v3 00/32] Rust binding for QAPI and qemu-ga QMP handler examples marcandre.lureau
2021-09-07 12:19 ` [RFC v3 01/32] RFC: docs: add supported host CPUs section marcandre.lureau
2021-09-07 12:33   ` Peter Maydell
2021-09-13 11:32     ` Marc-André Lureau
2021-09-13 11:46       ` Peter Maydell
2021-09-07 12:19 ` [RFC v3 02/32] build-sys: add HAVE_IPPROTO_MPTCP marcandre.lureau
2021-09-08 12:01   ` Markus Armbruster
2021-09-13 13:02   ` Paolo Bonzini
2021-09-07 12:19 ` [RFC v3 03/32] scripts/qapi: teach c_param_type() to return const argument type marcandre.lureau
2021-09-08 12:10   ` Markus Armbruster
2021-09-08 14:33     ` Marc-André Lureau
2021-09-07 12:19 ` [RFC v3 04/32] glib-compat: add G_SIZEOF_MEMBER marcandre.lureau
2021-09-08 12:16   ` Markus Armbruster
2021-09-08 13:49     ` Marc-André Lureau
2021-09-07 12:19 ` [RFC v3 05/32] scripts/qapi: add QAPISchemaVisitor.visit_module_end marcandre.lureau
2021-09-08 12:26   ` Markus Armbruster
2021-09-07 12:19 ` [RFC v3 06/32] scripts/qapi: add a CABI module marcandre.lureau
2021-09-07 12:19 ` [RFC v3 07/32] scripts/qapi: generate CABI dump for C types marcandre.lureau
2021-09-07 12:19 ` [RFC v3 08/32] tests: build qapi-cabi (C ABI dump) marcandre.lureau
2021-09-07 12:19 ` [RFC v3 09/32] build-sys: add i686 cpu target marcandre.lureau
2021-09-08 13:45   ` Peter Maydell
2021-09-07 12:19 ` [RFC v3 10/32] build-sys: add --with-rust{-target} & basic build infrastructure marcandre.lureau
2021-09-08 14:00   ` Peter Maydell
2021-09-08 14:21     ` Marc-André Lureau
2021-09-07 12:19 ` [RFC v3 11/32] build-sys: add a cargo-wrapper script marcandre.lureau
2021-09-07 12:19 ` [RFC v3 12/32] rust: provide a common crate for QEMU marcandre.lureau
2021-09-10  1:18   ` Alistair Francis
2021-09-10  7:43     ` Marc-André Lureau
2021-09-13 17:11   ` Paolo Bonzini
2021-09-14 11:34     ` Marc-André Lureau [this message]
2021-09-07 12:19 ` [RFC v3 13/32] rust: use vendored-sources marcandre.lureau
2021-09-08 15:38   ` Ian Jackson
2021-09-08 15:47     ` Marc-André Lureau
2021-09-08 15:55       ` Ian Jackson
2021-09-08 16:15         ` Marc-André Lureau
2021-09-08 16:22           ` Peter Maydell
2021-09-08 16:22           ` Ian Jackson
2021-09-08 16:20     ` Marc-André Lureau
2021-09-08 16:29       ` Ian Jackson
2021-09-08 16:34         ` Marc-André Lureau
2021-09-08 16:50           ` Ian Jackson
2021-09-08 19:33             ` Marc-André Lureau
2021-09-09 16:02   ` Peter Maydell
2021-09-09 16:29     ` Marc-André Lureau
2021-09-09 16:53       ` Daniel P. Berrangé
2021-09-09 17:04         ` Ian Jackson
2021-09-13 14:21       ` Paolo Bonzini
2021-09-09 16:49     ` Daniel P. Berrangé
2021-09-09 17:02       ` Ian Jackson
2021-09-07 12:19 ` [RFC v3 14/32] scripts/qapi: add QAPISchemaIfCond.rsgen() marcandre.lureau
2021-09-08 12:33   ` Markus Armbruster
2021-09-08 14:06     ` Marc-André Lureau
2021-09-07 12:19 ` [RFC v3 15/32] scripts/qapi: strip trailing whitespaces marcandre.lureau
2021-09-07 12:19 ` [RFC v3 16/32] scripts/qapi: add Rust FFI bindings generation marcandre.lureau
2021-09-07 12:19 ` [RFC v3 17/32] scripts/qapi: learn to generate ABI dump for Rust FFI marcandre.lureau
2021-09-07 12:19 ` [RFC v3 18/32] tests: generate Rust bindings marcandre.lureau
2021-09-07 12:19 ` [RFC v3 19/32] tests: check Rust and C CABI diffs marcandre.lureau
2021-09-07 12:19 ` [RFC v3 20/32] scripts/qapi: generate high-level Rust bindings marcandre.lureau
2021-09-07 12:19 ` [RFC v3 21/32] tests/rust: build a common library, checking bindings compile marcandre.lureau
2021-09-07 12:19 ` [RFC v3 22/32] qga: build qapi-cabi binary (ABI from C) marcandre.lureau
2021-09-07 12:19 ` [RFC v3 23/32] qga/rust: build and link an empty static library marcandre.lureau
2021-09-07 12:19 ` [RFC v3 24/32] qga/rust: generate QGA QAPI types FFI bindings marcandre.lureau
2021-09-07 12:19 ` [RFC v3 25/32] qga/rust: build a qga-cabi-rs executable (ABI from Rust) marcandre.lureau
2021-09-07 12:19 ` [RFC v3 26/32] qga/rust: check the Rust C binding marcandre.lureau
2021-09-07 12:19 ` [RFC v3 27/32] qga/rust: build high-level Rust QAPI types marcandre.lureau
2021-09-07 12:19 ` [RFC v3 28/32] qga/rust: implement get-host-name in Rust (example) marcandre.lureau
2021-09-07 12:19 ` [RFC v3 29/32] qga/rust: implement {get,set}-vcpus " marcandre.lureau
2021-09-07 12:19 ` [RFC v3 30/32] tests/vm: add Rust to FreeBSD VM marcandre.lureau
2021-09-07 12:19 ` [RFC v3 31/32] tests/vm: bump fedora VM to f32 marcandre.lureau
2021-09-07 12:19 ` [RFC v3 32/32] tests/vm: add Rust to Fedora marcandre.lureau
2021-09-08 13:22 ` [RFC v3 00/32] Rust binding for QAPI and qemu-ga QMP handler examples Markus Armbruster
2021-09-08 13:55   ` Marc-André Lureau
2021-09-09 10:31     ` Markus Armbruster
2021-09-09 15:22       ` Marc-André Lureau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAJ+F1CK4s-D+Rwz6EG9+mUxb8EUJJuphF5Ox+gtsEq+CNL7zAQ@mail.gmail.com \
    --to=marcandre.lureau@gmail.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.