From f173fe3defbbee85886787035ee30ad9dd9cc486 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 09:05:24 -0700 Subject: [PATCH 1/4] chore(quest): claim quest/m1/c/name-clash.md Quest-Claim: 22ba9ae6cd0ef459 From b884c1250b4343b82d5512bb9de9c9f09afcaff3 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 09:07:42 -0700 Subject: [PATCH 2/4] docs(quest): record C generator naming decision Co-Authored-By: GPT-6 --- quest/m1/c/name-clash.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/quest/m1/c/name-clash.md b/quest/m1/c/name-clash.md index 98ca21d8257..ab25577de34 100644 --- a/quest/m1/c/name-clash.md +++ b/quest/m1/c/name-clash.md @@ -16,4 +16,25 @@ The generator lives in [kixelated/rust2](https://github.com/kixelated/rust2)'s UniFFI fork (`uniffi/`), so the work lands there. This quest stands in for it until moq builds from a fork that ships the fix. -Public API: the C names of the pairs the generator renames. Wire: none. +The implementation is in +`uniffi/cpp/bindgen/src/bindings/c/gen_c.rs` in rust2. `Gen::render` reserves +all type names first, `render_object` then names each method +`_`, and `claim` refuses a duplicate rather than generating an +invalid header. The same ambiguity reaches constructors, generated `_free` +functions, and async `_callback` typedefs; changing only `finish` leaves the +naming rule ambiguous. + +Open maintainer decision: choose the generated C naming rule before changing +symbols. Recommendation: put methods under an explicit method namespace, for +example `moq_audio_encoder_method_finish`, while preserving record names. +Alternative: change generated type names uniformly and preserve the short +function names. Check the chosen rule against constructors, release functions, +async callbacks, and normalized-name collisions, with a compiled C fixture in +rust2. No moq-ffi item should be renamed. + +After the generator fix lands, update moq's generator pin to a revision that +contains it and prove that the moq-ffi header generates and compiles. Today +`flake.nix` still consumes the separate `kixelated/uniffi-bindgen-cpp` fork; +the fix must reach the generator moq actually builds. + +Public API: the generated C symbols changed by the chosen naming rule. Wire: none. From ec66733e0d8f6c6e6784ef09323af20068f20cc3 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 15:55:35 -0700 Subject: [PATCH 3/4] docs(quest): record the generated C method namespace rule Co-Authored-By: Claude Opus 5.5 --- quest/m1/c/README.md | 2 +- quest/m1/c/name-clash.md | 69 +++++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/quest/m1/c/README.md b/quest/m1/c/README.md index f9bb64c8e73..9f75c16f642 100644 --- a/quest/m1/c/README.md +++ b/quest/m1/c/README.md @@ -65,7 +65,7 @@ requests internally and keeps its ABI. ## Required -- [One C name per moq-ffi item](/quest/m1/c/name-clash.md) - rust2's C generator derives collision-free names, so `MoqAudioEncoder::finish` and `MoqAudioEncoderFinish` stop sharing `moq_audio_encoder_finish` +- [One C name per moq-ffi item](/quest/m1/c/name-clash.md) - rust2's C generator gives methods an explicit namespace, so `MoqAudioEncoder::finish` and `MoqAudioEncoderFinish` stop sharing `moq_audio_encoder_finish` - [moq-c package](/quest/m1/c/package.md) - the generated header ships as `moq-c` 0.8.0 with `moq::c`, pkg-config, and a release workflow - [C consumers](/quest/m1/c/consumers.md) - the C interop client and `doc/lib/c` samples move onto the generated API - [Async failure contract](/quest/m1/c/async-failure-contract.md) - a generated async call that fails early fires no callback, and one that started always delivers its terminal callback diff --git a/quest/m1/c/name-clash.md b/quest/m1/c/name-clash.md index ab25577de34..9c59c4f9ef8 100644 --- a/quest/m1/c/name-clash.md +++ b/quest/m1/c/name-clash.md @@ -1,40 +1,45 @@ -# [S] One C name per moq-ffi item +# [XS] One C name per moq-ffi item ## Goal The generated C header gives every moq-ffi item its own name. Today the method `MoqAudioEncoder::finish` and the record `MoqAudioEncoderFinish` both map to -`moq_audio_encoder_finish`. +`moq_audio_encoder_finish`. Waiting on [kixelated/rust2#66](https://github.com/kixelated/rust2/pull/66), which implements the rule +below; delete this quest once it merges. ## Plan -Decided with the maintainer on 2026-10-24: fix the C generator, not moq-ffi. The -generator derives collision-free names, for example by qualifying a method with -its type, so no moq-ffi item is renamed. - -The generator lives in [kixelated/rust2](https://github.com/kixelated/rust2)'s -UniFFI fork (`uniffi/`), so the work lands there. This quest stands in for it -until moq builds from a fork that ships the fix. - -The implementation is in -`uniffi/cpp/bindgen/src/bindings/c/gen_c.rs` in rust2. `Gen::render` reserves -all type names first, `render_object` then names each method -`_`, and `claim` refuses a duplicate rather than generating an -invalid header. The same ambiguity reaches constructors, generated `_free` -functions, and async `_callback` typedefs; changing only `finish` leaves the -naming rule ambiguous. - -Open maintainer decision: choose the generated C naming rule before changing -symbols. Recommendation: put methods under an explicit method namespace, for -example `moq_audio_encoder_method_finish`, while preserving record names. -Alternative: change generated type names uniformly and preserve the short -function names. Check the chosen rule against constructors, release functions, -async callbacks, and normalized-name collisions, with a compiled C fixture in -rust2. No moq-ffi item should be renamed. - -After the generator fix lands, update moq's generator pin to a revision that -contains it and prove that the moq-ffi header generates and compiles. Today -`flake.nix` still consumes the separate `kixelated/uniffi-bindgen-cpp` fork; -the fix must reach the generator moq actually builds. - -Public API: the generated C symbols changed by the chosen naming rule. Wire: none. +Decided with the maintainer on 2026-10-24: fix the C generator, not moq-ffi, so +no moq-ffi item is renamed. Decided 2026-10-25: the fix lands in rust2's UniFFI +fork (`uniffi/cpp/bindgen/src/bindings/c/gen_c.rs`), not in a +`kixelated/uniffi-bindgen-cpp` release, and the rule is an explicit method +namespace rather than a uniform type naming change, so types keep the short +names C users write most. + +The rule: + +- Types keep `_`. +- Methods and named constructors are `_method_`: + `moq_audio_encoder_method_finish`, beside the record + `moq_audio_encoder_finish`. +- The generator's fixed names stay: the primary constructor `_new`, the + release functions `_free`, `_default`, and `_message`. +- An async call's callback typedef is its function's name plus `_callback`, so + a method's moves with it. +- Top-level functions keep `_`, and data-enum variant structs + keep `_`. +- Two items that still normalize to one name (`MoqFoo` and `Foo`, a function + and a type, a type named `Free`) are refused at generation with both + items named, and the Rust author renames one. + +Under the old rule moq-ffi had exactly that one clash; under this rule it has +none, and its header compiles as C11. That check stubbed `Duration`, which +moq-ffi now uses and the C backend still refuses, another drift the generated C +line must close. + +moq still builds C++ from `kixelated/uniffi-bindgen-cpp`; the rule reaches +moq's build through [Switch to rust2's UniFFI](/quest/m2/uniffi-fork.md), which +owns the pin, and the generated C line's CI build checks the header. + +Public API: the generated C names of methods and named constructors gain +`_method_`. Wire: none. From 7c9f2777a5d751501ed4f453e3a48a90f3731171 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 25 Oct 2026 16:56:09 -0700 Subject: [PATCH 4/4] docs(quest): the generated C names follow GLib, superseding _method_ Co-Authored-By: Claude Opus 5.5 --- quest/m1/c/README.md | 8 ++--- quest/m1/c/name-clash.md | 64 +++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/quest/m1/c/README.md b/quest/m1/c/README.md index 9f75c16f642..1722d4c5785 100644 --- a/quest/m1/c/README.md +++ b/quest/m1/c/README.md @@ -22,10 +22,10 @@ Decided: `moq_work_run`, the C form of `moq::set_executor`. Streams are repeated calls. This removes the trampolines and lock-order rules libmoq's single callback thread forced on hosts like OBS. -- Errors, records, and names mirror the C++ package: calls return `moq_error *` +- Errors and records mirror the C++ package: calls return `MoqError *` (NULL on success) with `moq_error_message()`, results come through - out-params, records are owned structs with `moq__free`, and names are - the uniffi names in snake case. + out-params, and records are owned structs with `moq__free`. Names + follow GLib: CamelCase types and snake_case functions. - The header is C11: errors and data enums are a `tag` plus an anonymous union (`err->protocol`). Infallible calls return their value directly, optional scalars are `{has_value, value}`, each async function has its own callback @@ -65,7 +65,7 @@ requests internally and keeps its ABI. ## Required -- [One C name per moq-ffi item](/quest/m1/c/name-clash.md) - rust2's C generator gives methods an explicit namespace, so `MoqAudioEncoder::finish` and `MoqAudioEncoderFinish` stop sharing `moq_audio_encoder_finish` +- [One C name per moq-ffi item](/quest/m1/c/name-clash.md) - rust2's C generator names types in CamelCase and functions in snake_case, so the record `MoqAudioEncoderFinish` and the method `moq_audio_encoder_finish` never share a name - [moq-c package](/quest/m1/c/package.md) - the generated header ships as `moq-c` 0.8.0 with `moq::c`, pkg-config, and a release workflow - [C consumers](/quest/m1/c/consumers.md) - the C interop client and `doc/lib/c` samples move onto the generated API - [Async failure contract](/quest/m1/c/async-failure-contract.md) - a generated async call that fails early fires no callback, and one that started always delivers its terminal callback diff --git a/quest/m1/c/name-clash.md b/quest/m1/c/name-clash.md index 9c59c4f9ef8..d55cba94d54 100644 --- a/quest/m1/c/name-clash.md +++ b/quest/m1/c/name-clash.md @@ -4,42 +4,60 @@ The generated C header gives every moq-ffi item its own name. Today the method `MoqAudioEncoder::finish` and the record `MoqAudioEncoderFinish` both map to -`moq_audio_encoder_finish`. Waiting on [kixelated/rust2#66](https://github.com/kixelated/rust2/pull/66), which implements the rule -below; delete this quest once it merges. +`moq_audio_encoder_finish`. Waiting on +[kixelated/rust2#66](https://github.com/kixelated/rust2/pull/66), which +implements the rule below; delete this quest once it merges. ## Plan Decided with the maintainer on 2026-10-24: fix the C generator, not moq-ffi, so no moq-ffi item is renamed. Decided 2026-10-25: the fix lands in rust2's UniFFI fork (`uniffi/cpp/bindgen/src/bindings/c/gen_c.rs`), not in a -`kixelated/uniffi-bindgen-cpp` release, and the rule is an explicit method -namespace rather than a uniform type naming change, so types keep the short -names C users write most. +`kixelated/uniffi-bindgen-cpp` release. + +The naming rule (maintainer, 2026-10-25): + +- ✅ GLib/GStreamer style: CamelCase types, snake_case functions +- Explicit method namespace (`moq_audio_encoder_method_finish`), chosen first + the same day and then superseded by the GLib rule +- Uniform type naming change while keeping short function names +- Path names plus a `[rename]` table + +Why: function calls read naturally (`moq_audio_encoder_finish(enc)`), C users +of GStreamer and OBS already know the convention, and a type can never share an +identifier with a function, so no rename table is needed. A rename table would +make names unpredictable: adding an item could silently rename an existing one. The rule: -- Types keep `_`. -- Methods and named constructors are `_method_`: - `moq_audio_encoder_method_finish`, beside the record - `moq_audio_encoder_finish`. -- The generator's fixed names stay: the primary constructor `_new`, the - release functions `_free`, `_default`, and `_message`. -- An async call's callback typedef is its function's name plus `_callback`, so - a method's moves with it. -- Top-level functions keep `_`, and data-enum variant structs - keep `_`. -- Two items that still normalize to one name (`MoqFoo` and `Foo`, a function - and a type, a type named `Free`) are refused at generation with both - items named, and the Rust author renames one. - -Under the old rule moq-ffi had exactly that one clash; under this rule it has +- Types are CamelCase with the namespace prefix: `MoqAudioEncoder`, + `MoqAudioEncoderFinish`, `MoqError`, `MoqTask`, compounds such as + `MoqStringList`, enum tags `Tag`, variant structs ``, + and async callback typedefs `Callback` + (`MoqAudioEncoderFinishCallback`). A type's name is its prefixed snake-case + name re-cased, so it is predictable from its functions' prefix. +- Functions stay snake_case with no infix: `moq_audio_encoder_finish`, + `moq_audio_encoder_new`, `moq_audio_encoder_free`, `moq_error_message`. Enum + constants stay `MOQ__`. +- Any clash that remains (two functions with one name, such as a method `free` + and the release function, or `MoqFoo` and `Foo`) is refused at generation + with both items named, and the Rust author renames one. + +rust2's own exporter (`ffi/`), which replaces the fork, adopts the same rule +instead of path names plus a `[rename]` table, so moq's C names do not change +again when it lands. + +Under the old rule moq-ffi had exactly the one clash; under this rule it has none, and its header compiles as C11. That check stubbed `Duration`, which moq-ffi now uses and the C backend still refuses, another drift the generated C line must close. moq still builds C++ from `kixelated/uniffi-bindgen-cpp`; the rule reaches moq's build through [Switch to rust2's UniFFI](/quest/m2/uniffi-fork.md), which -owns the pin, and the generated C line's CI build checks the header. +owns the pin, and the generated C line's CI build checks the header. The +generated moq-c package +([moq-dev/moq#6052](https://github.com/moq-dev/moq/pull/6052)) adopts these +names then. -Public API: the generated C names of methods and named constructors gain -`_method_`. Wire: none. +Public API: generated C type names become CamelCase; function names are +unchanged. Wire: none.