Skip to content

Conversation

@jswrenn
Copy link
Collaborator

@jswrenn jswrenn commented Dec 3, 2025

The HasField trait permits privacy-preserving field projections
from structs, enums and unions.

HasField preserves privacy by leveraging the scoped trait pattern;
for each field f, HasField is implemented with the Field parameter
set to a type with identical visibility as f. In many useful contexts,
this Field parameter is inferable, and need not be actually reachable.
Consequently, HasField can be used to index a field from only the name
of a field. See zerocopy-derive/tests/ui-nightly/privacy.rs for
examples.


This PR is on branch fields.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jswrenn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a foundational HasField trait and its corresponding derive macro, significantly enhancing the zerocopy crate's capabilities for compile-time introspection of struct fields. This new mechanism provides a structured way to query field metadata such as types, offsets, and unique identifiers, which is essential for advanced compile-time analysis and manipulation of data structures. The changes also include several internal improvements to macro utilities, streamlining offset calculations and refining trait handling within the derive system.

Highlights

  • New HasField Trait: Introduced an unsafe trait HasField that allows compile-time querying of a struct's field type, offset, and a unique FIELD_ID (a u128 hash). This trait is marked #[doc(hidden)] and is intended for internal derive macro usage.
  • Derive Macro for HasField: A new derive macro has been implemented to automatically generate HasField implementations for struct fields. This involves creating unique, hidden enum types for each field and calculating their respective offsets and IDs.
  • Field ID Hashing Mechanism: A new ident_id! macro and a hash_name const function were added to generate stable u128 identifiers for fields. This hashing is designed to be deterministic within a compilation and is crucial for the FIELD_ID constant in the HasField trait.
  • Improved trailing_field_offset! Macro: The trailing_field_offset! macro has been refined to directly return a usize value instead of an Option<usize>, indicating a more robust and guaranteed calculation of field offsets. It also now uses fully qualified paths for internal constants.
  • Internal Derive Macro Refinements: Various internal improvements were made to the derive macro system, including using matches! for enum comparisons, updating the Trait enum to include HasField with generic arguments, and adjusting trait bound normalization to handle cloning of Trait values.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the HasField trait, which allows compile-time reflection on struct fields. The implementation includes a new derive macro for HasField and a compile-time hashing function for field identifiers. The changes are well-structured, but I found a bug in the ToTokens implementation for the Trait enum that will cause compilation failures for existing derives. My review includes a suggestion to fix this.

@jswrenn jswrenn force-pushed the G2238bc341570838db412d880017b3f0c25ac09fa branch from 9526d5d to 2b6d45e Compare December 4, 2025 15:24
@codecov-commenter
Copy link

codecov-commenter commented Dec 4, 2025

Codecov Report

❌ Patch coverage is 0% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.05%. Comparing base (60f4102) to head (bced22a).

Files with missing lines Patch % Lines
src/util/macro_util.rs 0.00% 18 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2842      +/-   ##
==========================================
- Coverage   92.33%   92.05%   -0.29%     
==========================================
  Files          20       20              
  Lines        5794     5812      +18     
==========================================
  Hits         5350     5350              
- Misses        444      462      +18     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jswrenn jswrenn force-pushed the G2238bc341570838db412d880017b3f0c25ac09fa branch from 2b6d45e to e5dae4c Compare December 4, 2025 17:27
@jswrenn jswrenn changed the title introduce HasField Introduce HasField trait Dec 4, 2025
@jswrenn jswrenn force-pushed the G2238bc341570838db412d880017b3f0c25ac09fa branch 5 times, most recently from cff59b0 to e738a09 Compare December 4, 2025 17:44
The `HasField` trait permits privacy-preserving field projections
from structs, enums and unions.

`HasField` preserves privacy by leveraging the [scoped trait pattern];
for each field `f`, `HasField` is implemented with the `Field` parameter
set to a type with identical visibility as `f`. In many useful contexts,
this `Field` parameter is inferable, and need not be actually reachable.
Consequently, `HasField` can be used to index a field from only the name
of a field. See `zerocopy-derive/tests/ui-nightly/privacy.rs` for
examples.

[scoped trait pattern]: https://jack.wrenn.fyi/blog/private-trait-impls/

gherrit-pr-id: G2238bc341570838db412d880017b3f0c25ac09fa
@jswrenn jswrenn force-pushed the G2238bc341570838db412d880017b3f0c25ac09fa branch from e738a09 to bced22a Compare December 4, 2025 17:47
// Since Rust does not presently support explicit visibility
// modifiers on enum fields, any public type is suitable
// here; we use `()`.
field: parse_quote!(()),
Copy link
Member

Choose a reason for hiding this comment

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

Feel free to disregard, but it might be worth considering whether we could put this in a const or static or something to avoid recomputing it for every field.

FieldBounds::TRAILING_SELF
};
let require_trait_bound_on_field_types =
if matches!(self_bounds, SelfBounds::All(&[Trait::Sized])) {
Copy link
Member

Choose a reason for hiding this comment

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

Is this a breaking change?

Comment on lines +750 to +753

if fields.is_empty() {
return quote! {};
}
Copy link
Member

Choose a reason for hiding this comment

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

Style uber-nit; feel free to disregard.

Suggested change
if fields.is_empty() {
return quote! {};
}
if fields.is_empty() {
return quote! {};
}

});

let has_fields = fields.iter().map(|(_, ident, ty)| {
let field_token = Ident::new(&format!("ẕ{}", ident), ident.span());
Copy link
Member

Choose a reason for hiding this comment

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

Same here re: __Zerocopy_ prefix.

ast,
data,
Trait::HasField {
variant_id: parse_quote!({ #zerocopy_crate::ident_id!(0) }),
Copy link
Member

Choose a reason for hiding this comment

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

If this is for a variant, why is it always 0? Shouldn't it be the ID of the variant in question?

@@ -0,0 +1,102 @@
// Copyright 2019 The Fuchsia Authors
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Copyright 2019 The Fuchsia Authors
// Copyright 2025 The Fuchsia Authors

Comment on lines +16 to +18
// These tests cause errors which are generated by a later compilation pass than
// the other errors we generate, and so if they're compiled in the same file,
// the compiler will never get to that pass, and so we won't get the errors.
Copy link
Member

Choose a reason for hiding this comment

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

That comment only makes sense in the late_compile_pass.rs test IMO. Is it true for this file too?

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.

3 participants