public inbox for qemu-rust@nongnu.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-devel@nongnu.org,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	qemu-rust@nongnu.org
Subject: Re: [PATCH v2 12/16] scripts/qapi: generate high-level Rust bindings
Date: Wed, 04 Mar 2026 09:09:42 +0100	[thread overview]
Message-ID: <87bjh4koc9.fsf@pond.sub.org> (raw)
In-Reply-To: <CABgObfYBVbpLfzFiYaCjzTL5zTqynWcUepV=o-AesJJF3jENEQ@mail.gmail.com> (Paolo Bonzini's message of "Tue, 3 Mar 2026 16:55:30 +0100")

Paolo Bonzini <pbonzini@redhat.com> writes:

> On Tue, Mar 3, 2026 at 1:31 PM Markus Armbruster <armbru@redhat.com> wrote:
>
>> >> You replied "In this case it doesn't really matter: public items (such
>> >> as QAPI enum entries, or struct fields) do not raise the unused warning
>> >> anyway."
>> >>
>> >> What gives us confidence rs_name() will only be used where it doesn't
>> >> really matter?
>> >
>> > The fact that all QAPI type definitions are (more or less by design) public.
>>
>> Any particular reason not to use the same 'q_' prefix as in C?
>
> The other Rust convention is that you usually have enums in CamelCase
> (starting with an uppercase letter). "q_" or "Q_" would also trigger a
> warning, and they would complicate to_camel_case a bit (because the
> prefix would have to be kept including the underscore).

Alright.

One of the QAPI generator's known shortcomings is weak protection
against name clashes in generated code.

The generator was built with cavalier disregard for name clashes.  The
existing naming rules and their enforcement was retrofitted to limit the
damage.

There are two kinds:

* The user's names clashing with the generator's.

  Naming rules help avoid such clashes.

  Example: ['Frob'] makes the generator define a C type FrobList, which
  could clash with a user-defined 'FrobList' if we didn't reject
  user-defined names ending with 'List'.  Test case reserved-type-list.

  But there are gaps.

  Example: a user-defined type QAPIEvent clashes with generated enum
  QAPIEvent.

  The naming rules should reflect the names the generator wants to use.
  When we add new patterns of generated names, we should update the
  rules.  One pattern this series adds is names ending with 'Variant',
  as I pointed out in the review of the generated code I sent yesterday.

* The user's names clashing with themselves.

  Naming rules again help avoid such clashes.

  Example: struct members 'a_b and 'a-b' would both map to C identifier
  a_b if we didn't reject that.  Test case struct-member-name-clash.

  The rejection code checks for clashes among the values of c_name().
  This guards against clashes in generated C.  To also guard against
  clashes in generated Rust, we'd need to check the values of rs_name().
  I'd accept a TODO comment for now.

  Again, there are gaps.

  Example: value 'ni-cator' of enum 'Frob' and value 'cator' of enum
  'FrobNi' both generate C enumeration constant FROB_NI_CATOR.

  The more the generator massages names, the more we risk such clashes.
  The C generator doesn't massage all that much, mostly funny characters
  to '_', and enumeration constants.  The Rust generator needs to
  massage more, because Rust's naming rules differ from C's.  I think we
  should at least document the problem clearly.  Anything else?  Better
  ideas?

See also docs/devel/qapi-code-gen.rst section "Naming rules and reserved
names".

>> >> This maps 'foo-0123-bar' to 'Foo_0123Bar'.  Intentional?  I'd kind of
>> >> expect 'Foo0123Bar'.
>> >
>> > Will fix (it is meant for 0123-45).  New version is:
>> >
>> >    def to_camel_case(value: str) -> str:
>> >        result = ''
>> >        for p in re.split(r'[-_]+', value):
>> >            if not p:
>> >                pass
>> >            elif p[0].isalpha() or (result and result[-1].isalpha()):
>> >                result += p[0].upper() + p[1:]
>> >            else:
>> >                result += '_' + p
>> >        return result
>>
>> Maps '0123-45' to '_0123_45'.  Is the leading '_' intentional?
>
> Yes, because otherwise the output is not an identifier; but it doesn't
> matter since the input is actually an identifier already and
> to_camel_case('_0123_45') does give '_0123_45'. In neither case you
> get the invalid identifier '0123_45'.

Shouldn't that be left to rs_name()?

>> I'm fine with not running rustfmt, and I'm fine with running it always
>> (makes it a hard requirement).  Running it sometimes feels like more
>> trouble than it's worth.
>
> Yeah, I will drop it. I changed mcgen to allow removing empty lines in
> the middle of a declaration, like this:
>
> def mcgen(*code: T.Sequence[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 = len(code) - 1
>     result = []
>     for i, s in enumerate(code):
>         if s.startswith('\n'):
>             s = s[1:]
>         if i != last:
>             s = s.rstrip()
>         s = cgen(s, **kwds)
>         if s:
>             result.append(s)
>     return '\n'.join(result)
>
> For the case of a single argument, the result is equivalent to the
> existing implementation:
>
>         # already checked by current mcgen()
>         if s.startswith('\n'):
>             s = s[1:]
>         # skipped for a single argument
>         if i != last:
>             s = s.rstrip()
>         s = cgen(s, **kwds)
>         if s:
>             result.append(s)
>     # result has zero or a single element, no '\n' added
>     return '\n'.join(result)

I wonder how the generated C would change if we used this there.



  reply	other threads:[~2026-03-04  8:09 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-08 13:10 [PATCH v2 00/16] rust: QObject and QAPI bindings Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 01/16] rust/qobject: add basic bindings Paolo Bonzini
2026-02-24 10:03   ` Markus Armbruster
2026-02-24 10:35     ` Paolo Bonzini
2026-02-24 13:33       ` Markus Armbruster
2026-02-25  8:05         ` Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 02/16] subprojects: add serde Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 03/16] rust/qobject: add Serialize implementation Paolo Bonzini
2026-02-24 10:29   ` Markus Armbruster
2026-02-24 10:48     ` Paolo Bonzini
2026-02-24 13:41       ` Markus Armbruster
2026-01-08 13:10 ` [PATCH v2 04/16] rust/qobject: add Serializer (to_qobject) implementation Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 05/16] rust/qobject: add Deserialize implementation Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 06/16] rust/qobject: add Deserializer (from_qobject) implementation Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 07/16] rust/qobject: add from/to JSON bindings for QObject Paolo Bonzini
2026-01-15 13:17   ` Zhao Liu
2026-01-08 13:10 ` [PATCH v2 08/16] rust/qobject: add Display/Debug Paolo Bonzini
2026-01-15 13:19   ` Zhao Liu
2026-01-08 13:10 ` [PATCH v2 09/16] scripts/qapi: add QAPISchemaIfCond.rsgen() Paolo Bonzini
2026-01-19  6:58   ` Zhao Liu
2026-02-25  6:48   ` Markus Armbruster
2026-02-25  7:53     ` Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 10/16] scripts/qapi: add QAPISchemaType.is_predefined Paolo Bonzini
2026-02-25  7:33   ` Markus Armbruster
2026-02-25  8:01     ` Paolo Bonzini
2026-02-25  8:44       ` Markus Armbruster
2026-02-26 14:12         ` Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 11/16] scripts/qapi: pull c_name from camel_to_upper to caller Paolo Bonzini
2026-01-19  7:05   ` Zhao Liu
2026-02-25  8:32   ` Markus Armbruster
2026-03-31  7:33     ` Paolo Bonzini
2026-03-31  7:37       ` Markus Armbruster
2026-01-08 13:10 ` [PATCH v2 12/16] scripts/qapi: generate high-level Rust bindings Paolo Bonzini
2026-02-23 12:36   ` Markus Armbruster
2026-02-23 16:11     ` Paolo Bonzini
2026-02-24 13:46       ` Markus Armbruster
2026-02-25 14:39   ` Markus Armbruster
2026-03-03 10:00     ` Paolo Bonzini
2026-03-03 12:31       ` Markus Armbruster
2026-03-03 15:55         ` Paolo Bonzini
2026-03-04  8:09           ` Markus Armbruster [this message]
2026-03-31  7:53             ` Paolo Bonzini
2026-03-03  9:19   ` Markus Armbruster
2026-03-03 13:17     ` Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 13/16] scripts/rustc_args: add --no-strict-cfg Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 14/16] rust/util: build QAPI types Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 15/16] scripts/qapi: add serde attributes Paolo Bonzini
2026-01-08 13:10 ` [PATCH v2 16/16] rust/tests: QAPI integration tests Paolo Bonzini
2026-02-17  8:10 ` [PATCH v2 00/16] rust: QObject and QAPI bindings Paolo Bonzini
2026-02-19 13:39 ` Markus Armbruster
2026-02-19 16:28   ` Paolo Bonzini
2026-02-23  9:53 ` Daniel P. Berrangé
2026-02-23 15:54   ` Paolo Bonzini
2026-02-23 16:24     ` Daniel P. Berrangé
2026-02-23 19:03       ` Paolo Bonzini
2026-02-24 14:06 ` Markus Armbruster
2026-02-24 17:28   ` Paolo Bonzini
2026-02-26 12:42     ` Markus Armbruster

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=87bjh4koc9.fsf@pond.sub.org \
    --to=armbru@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-rust@nongnu.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox