Skip to content

feat(ffi)!: name a field apart from the method of its name with field@ - #145

Merged
kixelated merged 4 commits into
mainfrom
quest/m1/ffi-export/crates
Oct 28, 2026
Merged

kixelated merged 4 commits into
mainfrom
quest/m1/ffi-export/crates

Conversation

@kixelated

@kixelated kixelated commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

A field and a method of one name claim one C name, and rename keys by path, so it could not tell them apart. moq's config excluded moq-tokio's Backoff::{initial,max,timeout} both ways, though moq-ffi reads the methods (the resolved values) and writes the fields.

Approach

exclude and rename name a field as rustdoc's intra-doc links do: a path a method or constant shares with a field names the method, and field@ before it names the field. A field no method shares keeps its bare path, so no other config changes.

  • Collect: a field is shared when a pub inherent method or constant has its name, from an impl that applies to the instance and with bounds the instance meets, as methods() checks. Its exclude matches field@<path>, or the bare path when not shared. A refused shared field is reported, and listed in the census, as field@<path>.
  • ABI: a getter takes a field@ rename first, and a bare one only when not shared. A clash names a getter field, not fn, and its help points at field@.
  • moq: the three Backoff excludes go. field@Backoff::{initial,max,timeout} rename the fields to backoff_<field>_setting, so moq_backoff_initial returns the resolved moq_duration and moq_backoff_initial_setting the configured moq_cli_duration or null. Log::level's field, refused for a foreign type, now needs its own field@Log::level exclude. moq/moq.c reads both on a default backoff.
  • Tests: the api fixture's Retry renames one field with field@ and excludes another with field@, keeping its method; the C transcript matches native Rust. Its generic Slot has a value() method only on Slot<u8>, so a bare path excludes Slot<u32>'s field and field@ excludes Slot<u8>'s. The reject fixture's Limit clashes without a rename, and a field@ rename of a missing field is an error.
  • Quest: what remains of crates is moq-clock's names (moq_now, moq_origin), which wait on moq's kio::clock quest. It is rewritten to that wait.

Consumer: moq's export (just ffi moq), which now exports the 6 Backoff functions it left out.

Impact

  • ffi.toml (breaking): a bare exclude or rename path that a field shares with a method or constant of its instance now names only the method. A config that relied on it naming both needs a field@ entry for the field. New ffi/MIGRATE.md records it.
  • ffi.toml: field@<path> names a field in exclude and rename.
  • IR: Access::Field carries shared.
  • moq's C API: gains moq_backoff_{initial,max,timeout} and moq_backoff_{initial,max,timeout}_setting.

Decided

  • Field and method of one name (maintainer, 2026-10-27): field@ in the config now, as this PR does. The newest AGENTS.md rule makes it a config gap; a C naming rule that retires moq's renames will close it, planned separately. Rejected: every object getter as <type>_get_<field> (renames every getter, and get_x methods still clash), and a rule suffix on shared fields only (adding a method silently renames a getter).

Choices made without asking:

  • Bare paths resolve as rustdoc does (method first) instead of naming both.
  • The field names are backoff_<field>_setting, by role: the field is the setting as configured, and the method resolves its default.
  • The quest file keeps its path (crates.md) under its new title, so its branch claim holds.

Alternatives

  • Method wins and the field is left out by rule (recommended in #94): silent, and the getter is the only way to tell an unset setting from its default.
  • field@ required on every field: Rust-faithful too, but it rewrites about 60 field excludes in moq's config for no gain.

Follow-ups

  • Field setters: moq-ffi writes Backoff's fields (connect.backoff.initial = ...), and the export has only getters.
  • C names without rename: a naming rule that needs no rename for moq's 24 clashes, which the maintainer will plan separately.

Checks

  • just check: passed.
  • just ffi test: 14 passed.
  • just ffi moq: moq's export at the pin builds, and moq/moq.c passes.
  • just ffi census: no clashes; moq-tokio's exclude list matches the config.
  • just test: passed (ts, ffi, driver, uniffi).

(written by Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits October 27, 2026 19:35
A field and a method of one name claimed one C name that `rename` could
not split, so moq's config excluded moq-tokio's `Backoff::{initial,max,timeout}`
both ways. As in rustdoc, a path a method or constant shares with a field now
names the method, and `field@` before it names the field, in `exclude` and
`rename`. moq exports both: `moq_backoff_initial` resolves the default and
`moq_backoff_initial_setting` reads the field.

The quest keeps what remains: moq-clock's C names, which wait on moq moving
it into kio::clock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title One library from several crates feat(ffi)!: name a field apart from the method of its name with field@ Oct 28, 2026
@kixelated
kixelated marked this pull request as ready for review October 28, 2026 06:42
@kixelated

Copy link
Copy Markdown
Collaborator Author

Decision (maintainer, 2026-10-27): a field and the method of its name are told apart by field@ in the config, as this PR does. A C naming rule that retires moq's renames, closing this config gap, will be planned separately.

(written by Opus 5.5)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 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-28T07:05:52.489981Z 126f54b New commits
🔒 Security Review ✅ Completed 2026-10-28T07:08:56.703674Z 126f54b 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.

@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: 07906cecca

ℹ️ 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".

Comment thread ffi/src/collect.rs Resolved
Comment thread ffi/src/config.rs Resolved

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator 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: 07906ce

P2: Confirmed the existing impl-applicability finding at ffi/src/collect.rs:1184–1188. A method present only on Holder incorrectly makes Holder's field shared, invalidating a previously valid bare field exclusion. Reuse the instance/bound checks from methods() before setting shared, with a regression covering both instances. No duplicate inline comment added.

Direction: explicit field@ disambiguation is a focused way to preserve both configured and resolved getters without a blanket C naming change. The instance-sensitive lookup needs the same semantics as method collection. The independent migration-documentation concern is already recorded separately. No additional actionable bugs found.

Verification: static inspection of collection, ABI naming, config normalization, glue and fixtures only; I did not run tests or generate/compile the C bindings.

A method of another instance's impl, or whose bounds the instance fails,
no longer takes a field's bare path. Add ffi/MIGRATE.md for the breaking
config change.

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

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator 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: 844b72eedb5cd6ee4d74f22dd4f7c6ec6227e87b

The prior impl-applicability P2 is fixed: getters() now uses impl_args and applies, matching method collection, and the Slot<u8>/Slot<u32> fixture covers the instance-specific exclusion regression. The independently reported migration-documentation gap is also addressed in ffi/MIGRATE.md.

No new actionable bugs found in the update since 07906cecca18053e0394fb40ef8d372fdc21d72e. Direction: reusing the existing applicability checks is a focused fix with appropriate regression coverage, without introducing a second matching mechanism.

Verification: static inspection of the changed collection logic, existing applicability helpers, fixture/config/C transcript additions, and migration guidance only. I did not run tests or generate/compile bindings.

…rates

# Conflicts:
#	ffi/fixtures/reject/src/lib.rs
#	ffi/tests/api.c
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merging: CI Check passed on 126f54b, Codex reviewed that head with no findings, both earlier findings (impl applicability, MIGRATE.md) are fixed, and quest check against main passes. The field@ design was decided by the maintainer on 2026-10-27. #146 and #151 are still open, so whichever lands second combines its ffi/MIGRATE.md entry under ## Unreleased.

(written by Opus 5.5)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant