Repository navigation
Strip a type prefix, and always use the bundled tl::expected - #4
Conversation
`strip_type_prefix = "Foo"` names `FooClient` as `Client`, so a crate that prefixes its types for languages without namespaces needs no alias list in C++. It renames through uniffi's `rename`, which skips a constructor's error type and leaves `get_type` keyed by the old names, so the type oracle renames each type it renders as well and `sorted_types` looks types up by name. A rename onto an existing type fails generation. `error_style = "expected"` now always uses the bundled `tl::expected`, never `std::expected`, so bindings built at C++17 link with code built at C++23 instead of silently disagreeing on the type. With exceptions disabled, `value()` on an error aborts with a message instead of reaching `__builtin_unreachable()`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
uniffi.toml sets the generator fork's new `strip_type_prefix = "Moq"`, so moq-ffi's `MoqClient` is generated as `moq::Client` and moq.hpp drops its alias list and the `just cpp check` audit of it. The fork also makes `uniffi::expected` the bundled `tl::expected` at every C++ standard, so the MOQ_ABI link guard and the "C++ standard" docs go away, and `value()` on an error aborts with a message instead of being undefined. The check now builds the probe at C++23 over bindings at C++17 to prove they link. The generator pin is the head of kixelated/uniffi-bindgen-cpp#4 until that PR is released as v0.11.0-kixelated.5+v0.32.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Reviewed the full diff ahead of the
Non-blocking edge cases, none of which affect moq (one crate, C backend unused):
Added the release commit ( (Written by Claude Opus 5.5) |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f42a41584e
ℹ️ 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".
| let flat: HashMap<String, String> = renames | ||
| .values() | ||
| .flatten() | ||
| .filter_map(|(old, new)| Some((old.clone(), new.as_str()?.to_string()))) | ||
| .collect(); |
There was a problem hiding this comment.
Keep fallback renames scoped to their defining crate
When library mode generates multiple components, flattening the crate-keyed rename tables and copying the result to every component loses the type's module identity. If one generated crate strips FooError while another component imports an unrenamed FooError from a crate not present in renames—or two crates map the same spelling differently—renamed() rewrites that reference using this global entry even though the defining header retains the original name, producing uncompilable bindings. Preserve the crate/module key in the fallback mapping.
Useful? React with 👍 / 👎.
| let found = self | ||
| .ci | ||
| .iter_local_types() | ||
| .chain(self.ci.iter_external_types()) | ||
| .find(|t| type_name(t) == Some(name)); |
There was a problem hiding this comment.
Distinguish external types in dependency lookup
When stripping a prefix makes a local record share a simple name with an imported record—for example, local FooCoordinates becomes Coordinates while one of its fields is ext::Coordinates—this name-only, local-first lookup conflates the two. The dependency graph can consequently contain a false Coordinates -> Coordinates self-edge and report a cyclic dependency even though the C++ types are valid in separate namespaces. Use the module path as part of topology keys and lookup.
Useful? React with 👍 / 👎.
Two generator changes for moq's C++ package, which ship in one fork release (
v0.11.0-kixelated.5+v0.32.2) and one pin bump in moq-dev/moq.strip_type_prefix[bindings.cpp] strip_type_prefix = "Foo"names the records, objects, enums, and callback interfacesFooClient/FooErrorasClient/Error. A name continues only after an uppercase letter (Foobarstays), custom types keep their names (custom_typesis keyed by them), and a rename onto an existing type fails generation. moq-ffi prefixes every type withMoqfor languages without namespaces; with this,cpp/moqdrops its ~100-line alias list and each type has one name.It renames through
uniffi_bindgen::interface::rename(the same machinery as Kotlin'srenametable), but uniffi 0.32's visitor has two gaps:as_codetype) also renames every type it renders.ComponentInterface::get_typekeyed by the old names, sosorted_typeslooks types up by name instead.The C backend reads the same
[bindings.cpp]config but ignores this option: its names are snake case under the namespace, so the prefix is not redundant there.tl::expectedat every standard (BREAKING)error_style = "expected"usedstd::expectedwhen the standard library had it and the bundledtl::expectedotherwise, so bindings built at C++17 and code built at C++23 disagreed on the type. It now always uses the bundledtl::expected, which has the same members. With exceptions disabled,value()on an error printed nothing and hit__builtin_unreachable(); the vendored copy now printsuniffi: expected::value() called on an errorand aborts, like a misused future.Tests
expected-testgeneratesuniffi_c_apiwithstrip_type_prefix = "Capi"and checkscapi::Store::openand itscapi::Error, including a throwing constructor (the uniffi gap).expected-value-on-error-testchecks the abort message.strip-type-prefix-collision-testchecks the collision refusal.Locally: the full ctest suite (without memcheck; no valgrind here) passes with GCC 16,
cargo fmt --checkis clean, and the expected test syntax-checks with Clang 21 at C++17 with-fno-exceptions. moq'sjust cpp checkpasses against this generator (C++17, C++23, C++23 over C++17 bindings, pkg-config, doc samples).Open decisions
(Written by Claude Opus 5.5)
🤖 Generated with Claude Code