Conversation
|
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 Report✅ All modified and coverable lines are covered by tests. 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. 🚀 New features to boost your workflow:
|
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.
a077c96 to
3c58f15
Compare
jswrenn
left a comment
There was a problem hiding this comment.
This is a long-overdue addition to zerocopy! Here's some preliminary feedback.
| // `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. |
There was a problem hiding this comment.
| // `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.
| /// | ||
| /// 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. |
There was a problem hiding this comment.
| /// | |
| /// 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.
Co-authored-by: Jack Wrenn <me@jswrenn.com>
|
Hi @jswrenn 👋. Happy to hear! Accepted suggestions. Let me know how else I can help. Thanks |
What
Let
derive(IntoBytes)accept#[repr(C)]generic structs when everyfield has the same type. Only requires
T: IntoBytes— noUnalignedbound.
Why it's sound
#[repr(C)]struct, N fields all of typeT, no#[repr(align)]:field
isits ati * size_of::<T>(), size isN * size_of::<T>(),struct alignment is
align_of::<T>(). Everything's a multiple ofalignment, so no padding. If
T: IntoBytes, so is the struct.Why I want it
arkworks has things like:
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