Skip to content

Support structs with same type#3324

Draft
z-tech wants to merge 4 commits intogoogle:mainfrom
z-tech:z-tech/support-structs-with-same-type
Draft

Support structs with same type#3324
z-tech wants to merge 4 commits intogoogle:mainfrom
z-tech:z-tech/support-structs-with-same-type

Conversation

@z-tech
Copy link
Copy Markdown

@z-tech z-tech commented Apr 22, 2026

What

Let derive(IntoBytes) accept #[repr(C)] generic structs when every
field has the same type. Only requires T: IntoBytes — no Unaligned
bound.

Why it's sound

#[repr(C)] struct, N fields all of type T, no #[repr(align)]:
field i sits at i * size_of::<T>(), size is N * size_of::<T>(),
struct alignment is align_of::<T>(). Everything's a multiple of
alignment, so no padding. If T: IntoBytes, so is the struct.

Why I want it

arkworks has things like:

#[repr(C)]
pub struct QuadExtField<P: QuadExtConfig> {
    pub c0: P::BaseField,
    pub c1: P::BaseField,
}

Can't use repr(transparent) (two fields). Existing generic branch
wants P::BaseField: Unaligned, which it isn't (Montgomery form,
align 8). So today the only way to treat &[Fq2] as bytes is a
hand-written unsafe transmute.

With this, elems.as_bytes() just works.

Partially addresses #10

@google-cla
Copy link
Copy Markdown

google-cla Bot commented Apr 22, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.88%. Comparing base (a51752b) to head (1abe7d0).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3324   +/-   ##
=======================================
  Coverage   91.88%   91.88%           
=======================================
  Files          20       20           
  Lines        6076     6076           
=======================================
  Hits         5583     5583           
  Misses        493      493           

☔ 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.

A `#[repr(C)]` struct with two or more fields whose types all
share the same syntactic token tree has no padding: each field
sits at offset `i * size_of::<T>()`, which is a multiple of
`align_of::<T>()` (the struct's alignment), and the struct's
size `N * size_of::<T>()` is also a multiple of that alignment.
Requiring only `T: IntoBytes` is therefore sufficient to prove
that the struct is padding-free.

This accepts strictly more types than the existing generic
`repr(C)` branch, which demands that every field type also
implement `Unaligned`. The new branch applies when every field
type token-compares equal; syntactic equality keeps the rule
trivially sound without needing type-resolution machinery that
is unavailable to proc macros.

Partially addresses google#10.
@z-tech z-tech force-pushed the z-tech/support-structs-with-same-type branch from a077c96 to 3c58f15 Compare April 22, 2026 15:07
@z-tech
Copy link
Copy Markdown
Author

z-tech commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator

@jswrenn jswrenn left a comment

Choose a reason for hiding this comment

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

This is a long-overdue addition to zerocopy! Here's some preliminary feedback.

Comment on lines +175 to +178
// `AU16` has alignment > 1, so the non-homogeneous branch would have
// rejected it (see `ReprCGenericMultipleFields<_, AU16>` below). The
// homogeneous case accepts it because `N * size_of::<AU16>()` is a
// multiple of `align_of::<AU16>()`, so there's still no padding.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// `AU16` has alignment > 1, so the non-homogeneous branch would have
// rejected it (see `ReprCGenericMultipleFields<_, AU16>` below). The
// homogeneous case accepts it because `N * size_of::<AU16>()` is a
// multiple of `align_of::<AU16>()`, so there's still no padding.

No need to say so much. :) Comments in tests that reference the current implementation details of zerocopy are likely to fall out of date.

Comment on lines +119 to +127
///
/// Comparison is syntactic (tokens only), not semantic: `T` and `Self::T`
/// compare unequal even if they resolve to the same type. That's
/// deliberate — a proc macro has no type resolution, and the soundness
/// argument we rely on ("N copies of the same type ⇒ no padding under
/// `repr(C)`") only holds when the types are actually the same at the
/// Rust-layout level. Being strict here keeps the rule trivially sound;
/// users wanting the optimisation for type-alias-equal fields can spell
/// the fields with a single alias.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
///
/// Comparison is syntactic (tokens only), not semantic: `T` and `Self::T`
/// compare unequal even if they resolve to the same type. That's
/// deliberate — a proc macro has no type resolution, and the soundness
/// argument we rely on ("N copies of the same type ⇒ no padding under
/// `repr(C)`") only holds when the types are actually the same at the
/// Rust-layout level. Being strict here keeps the rule trivially sound;
/// users wanting the optimisation for type-alias-equal fields can spell
/// the fields with a single alias.

This is said at the use-site of all_fields_same_type and does not need to be repeated here.

Comment thread zerocopy-derive/src/derive/into_bytes.rs Outdated
@z-tech
Copy link
Copy Markdown
Author

z-tech commented Apr 22, 2026

Hi @jswrenn 👋. Happy to hear! Accepted suggestions. Let me know how else I can help. Thanks

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