diff --git a/quest/m1/c/README.md b/quest/m1/c/README.md index f9bb64c8e73..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 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 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 98ca21d8257..d55cba94d54 100644 --- a/quest/m1/c/name-clash.md +++ b/quest/m1/c/name-clash.md @@ -1,19 +1,63 @@ -# [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. +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. -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 naming rule (maintainer, 2026-10-25): -Public API: the C names of the pairs the generator renames. Wire: none. +- ✅ 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 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. The +generated moq-c package +([moq-dev/moq#6052](https://github.com/moq-dev/moq/pull/6052)) adopts these +names then. + +Public API: generated C type names become CamelCase; function names are +unchanged. Wire: none.