Skip to content

feat(uniffi)!: name generated C types in CamelCase, GLib style - #66

Merged
kixelated merged 4 commits into
mainfrom
fix/c-method-namespace
Oct 26, 2026
Merged

kixelated merged 4 commits into
mainfrom
fix/c-method-namespace

Conversation

@kixelated

@kixelated kixelated commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Problem

The C backend spelled types and functions the same way, in snake case, so a method could spell another type: moq-ffi's MoqAudioEncoder::finish and its record MoqAudioEncoderFinish both became moq_audio_encoder_finish, and generation refused moq-ffi. The refusal named only the C symbol, not the two items.

Approach

Names follow GLib and GStreamer: types are CamelCase, functions stay snake_case with no infix, both prefixed with the namespace. A type and a function can then never share an identifier, so no rename table is needed.

  • Types: MoqAudioEncoder, MoqAudioEncoderFinish, MoqError, the runtime's MoqTask, MoqWork, and MoqDispatcher, compounds such as MoqStringList, enum tags <Enum>Tag, variant structs <Enum><Variant>, and async callback typedefs <Function>Callback (MoqAudioEncoderFinishCallback). A type's name is its prefixed snake-case name re-cased, so it is predictable from its functions' prefix.
  • Functions are unchanged: moq_audio_encoder_finish(enc), moq_audio_encoder_new, moq_audio_encoder_free, moq_error_message. Enum constants stay MOQ_COLOR_RED.
  • Any clash that remains, such as two functions with one name (a method free and the release function) or two types (MoqFoo and Foo), is refused with both items named: the C backend names both record `X` and method `Y` `z`; rename one of them.
  • The C++ implementation file qualifies C types from the global namespace (::MoqError), since the C++ classes in namespace moq now share their names.

The maintainer chose this in moq-dev/moq#6793, replacing the _method_ namespace this PR first proposed. The reason: calls read naturally, C users of GStreamer and OBS already know the convention, and a rename table would make names unpredictable, since adding an item could silently rename an existing one.

The exporter (ffi/) adopts the same rule instead of path names plus a [rename] table, so moq's C names do not change again when it replaces this fork. That change belongs to the exporter's work, not this PR.

The c-api fixture gains CapiStore::stats returning CapiStoreStats, the same pair as moq-ffi's, and c_api calls both from C.

Impact

  • Generated C (breaking): every type name is CamelCase (app_my_object * is now AppMyObject *, app_task is AppTask, app_my_object_do_thing_callback is AppMyObjectDoThingCallback). Functions and enum constants keep their names. MIGRATE.md has the entry.
  • A C++ file that includes both the C and C++ headers and writes using namespace <ns>; sees each type name twice and must qualify it.
  • Rust API: none.

Validation

  • just uniffi cpp: all 31 C and C++ fixture tests pass.
  • moq-ffi at moq-dev/moq@17be545bea generates with no clash, and its moq.h compiles as C11 with -Wall -Wextra -Werror. That run stubbed Duration, which the backend still refuses; the C line in moq owns adding it. moq-ffi's type names have no acronyms, so its C types match its Rust names exactly.
  • just check and just uniffi test (158 passed).

Alternatives

  • _method_ namespace for methods (moq_audio_encoder_method_finish), this PR's first version. Superseded: function calls read worse and the convention is unfamiliar to C users.
  • Path names with a [rename] table, as the exporter does today. Rejected: names become unpredictable.
  • Rename one of the moq-ffi items. Rejected earlier: the generator, not each crate, should keep names apart.

Follow-ups

  • The exporter's naming moves to this rule; recorded above, and suggested to the maintainer as a quest.

🤖 Generated with Claude Code

(Written by Claude Opus 5.5)

The C backend joined a type's name and a method's, so moq-ffi's
MoqAudioEncoder::finish and MoqAudioEncoderFinish both became
moq_audio_encoder_finish. Methods and named constructors now go under
<type>_method_<name>, and a remaining clash names both items.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T23:56:34.673620Z 77b35a8 New commits
🔒 Security Review ✅ Completed 2026-10-25T23:58:05.052430Z 77b35a8 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: daaca02

No actionable bugs found in the changed generator and fixtures. The _method_ namespace is a straightforward fix for the method/record clash without renaming every type; retaining fixed constructor/free helpers and rejecting residual collisions keeps the rule predictable. All three callable entry points still claim their names, async callback names follow the renamed function, and the C fixtures exercise the new stats method alongside its namesake record. The breaking C API change is documented.

Verification: static inspection of the diff and surrounding generator/fixture code only. I did not run builds or tests, or independently reproduce the reported moq-ffi generation.

kixelated and others added 2 commits October 25, 2026 16:39
Replaces the _method_ namespace: types are CamelCase (MoqAudioEncoderFinish,
MoqTask, MoqAudioEncoderFinishCallback) and functions stay snake_case
(moq_audio_encoder_finish), so a type and a function never share a name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title feat(uniffi)!: put generated C methods under _method_ feat(uniffi)!: name generated C types in CamelCase, GLib style Oct 25, 2026

@kixelated kixelated left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 77b35a8

No actionable bugs found in the substantive update since daaca02. This supersedes the previously reviewed _method_ approach with CamelCase C types and unchanged snake_case functions. The consistent casing rule is simpler for callers than per-item renames; residual same-kind collisions are still rejected. Recursive global qualification covers nested and external C types inside C++ converters, while separate snake-case prefixes preserve free/default helpers and enum constants. Runtime and callback typedefs, fixtures, and migration guidance move together.

Verification: static inspection of the base-aware diff, generator and C/C++ templates only. I did not run builds/tests or independently reproduce the reported downstream generation. Main-branch FFI/TypeScript integrations were excluded from this PR-specific follow-up.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 77b35a81b8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Scalars and strings keep their C spelling; every other type is named from its snake case.
let (c, snake) = match kind {
Kind::Scalar | Kind::String | Kind::Optional(_) => (c, String::new()),
_ => (type_name(&c), c),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use snake-case names in generated error-release instructions

For every throwing callable, changing CType.c to CamelCase makes the ownership documentation in render_callable name a nonexistent release function. Both the async callback documentation and synchronous return documentation still interpolate err.c followed by _free, so the C API fixture now tells callers to use CapiError_free even though the declared function remains capi_error_free. Use err.snake for those function references so callers receive correct cleanup instructions.

AGENTS.md reference: AGENTS.md:L25-L25

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in f5a2b49: both the async callback doc and the synchronous return doc now name err.snake's _free. I reproduced it first: capi.h said CapiError_free. After the fix every _free named in the generated C headers is declared, and just uniffi cpp passes 31/31.

(written by Opus 5.5)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn

@kixelated kixelated left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: f5a2b49

No actionable bugs found in the two-line update since 77b35a8. The previous independent finding is fixed: uniffi/cpp/bindgen/src/bindings/c/gen_c.rs:1233,1325 now use err.snake, matching the release declaration at line 1049. Both async and synchronous error-ownership instructions are corrected. Reusing the existing function-name prefix is the minimal fix and preserves the chosen CamelCase-type/snake_case-function API.

Verification: GitHub-only static inspection of the ancestor-aware delta and surrounding type mapping, including external errors. I did not run builds/tests or independently verify the reported 31/31 result.

(Written by OpenAI Codex)

@kixelated
kixelated merged commit 186229f into main Oct 26, 2026
3 checks passed
@kixelated
kixelated deleted the fix/c-method-namespace branch October 27, 2026 20:32
kixelated added a commit to moq-dev/moq that referenced this pull request Oct 29, 2026
kixelated/rust2#66 merged the GLib C naming rule into rust2's fork, so
the waiting quest is done. Its remaining moq-side work (adopting the new
C type names, reverting the MoqAudioEncoderFinished rename, and the
Duration gap in rust2's C backend) moves to quest/m2/uniffi-fork.md,
which owns the generator pin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant