-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking Issue for enum access in offset_of #120141
Comments
Noting one potential limitation to offset_of with enums: without a way to set the discriminant, it cannot be used to manually initialize an enum. Blog post explainer of what I mean: https://onevariable.com/blog/pods-from-scratch/ Zulip thread for discussion: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Prior.20discussions.20for.20manually.20building.20an.20enum.3F/near/441992612 |
Stabilization Report - Abstract
Feature SummaryThe macro computes field offsets for both This macro accepts two argument. The first is the source type that // crate a
#![feature(offset_of_enum)]
#![feature(offset_of_nested)]
struct AStruct {
pub field: u8,
field2: u32,
}
enum AEnum {
Variant1(u8),
Variant2 {
field: u8
},
Variant3(AStruct),
}
struct ANestingStruct(AStruct);
// readings as of Rust 1.78.0
// DO NOT EXPECT THESE ASSERTIONS TO WORK ACROSS VERSIONS
fn main() {
assert_eq!(offset_of!(AStruct, field), 4);
assert_eq!(offset_of!(AStruct, field2), 0);
assert_eq!(offset_of!(AEnum, Variant2.field), 1);
assert_eq!(offset_of!(AEnum, Variant3.0.field), 8);
assert_eq!(offset_of!(ANestingStruct, 0.field), 4);
} By respecting privacy, suppose that in another crate // crate b
#![feature(offset_of_enum)]
#![feature(offset_of_nested)]
fn main() {
// these still work
assert_eq!(offset_of!(AStruct, field), 4);
assert_eq!(offset_of!(AEnum, Variant2.field), 1);
assert_eq!(offset_of!(AEnum, Variant3.0.field), 8);
// this does not compile because field2 is private here
// assert_eq!(offset_of!(AStruct, field2), 0);
// this does not compile because 0 is private here
// assert_eq!(offset_of!(ANestingStruct, 0.field), 4);
} DocumentationThe rustdoc of our Test cases and edge casesThe basic test cases for
Unresolved questionsThere has been discussion around in-place construction of |
I discovered that in Given that |
@rfcbot fcp merge |
Team member @Amanieu has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
I don't think this is a blocker: the discriminant isn't encoded as a real field with an offset, so it can't be represented with |
@rfcbot concern consistent-future-syntax Given that this item (unlike nested fields) isn't as urgent, and that we don't have any syntax for this elsewhere in the language (unlike nested fields), I'd like to make sure that either:
(We currently have pattern syntax for extracting fields, but the syntax proposed for |
The same syntax could be used for the proposed field_of! macro, RFC 3318. It could possibly be used for the proposed Outside of reflection-related macros, the syntax |
Marking lang nominated to discuss how we want the future landscape to look here, and how we want to provide this functionality. (There's enough of a use case for this; the question is syntax.) |
Hey @joshtriplett, is this scheduled for a meeting agenda? If possible, I'd love to observe that meeting! I'm still very interested in the ability to construct enums in-place for deserialization reasons |
It'll be in an upcoming meeting, but we don't have it scheduled for a particular date. cc @traviscross who would have a better idea of timing. |
With At See: https://rust.godbolt.org/z/jz8qc1Pqv Basically, we can emulate In-place construction is done by initializing fields in-place using /// initializes `dst` to be valid AnEnum::X containing the fields already initialized in `dst`
/// # Safety
/// - `dst` must be properly aligned pointing to an `AnEnum`
/// - `dst` must be valid for writes
/// - The value pointed at by `dst` must have all fields of variant `X` initialized and valid.
unsafe fn set_discriminant_x(dst: NonNull<()>) {
// All the reads that immediately write the same value to the same location
// get eliminated with alteast `opt-level=1` leaving only the discriminant write, if any.
let value = AnEnum::X {
a: dst.byte_add(offset_of!(AnEnum, X.a)).cast::<u32>().read(),
b: dst.byte_add(offset_of!(AnEnum, X.b)).cast::<u64>().read(),
c: dst.byte_add(offset_of!(AnEnum, X.c)).cast::<Box<str>>().read(),
};
dst.cast::<AnEnum>().write(value);
}
enum AnEnum {
X{ a: u32, b: u64, c: Box<str> },
Y([u8; 12]),
} Note: Ideally a derive macro is generating the above function. By using a function pointer you can set the discriminant in a type erased fashion as well. Of course, it would still be great to have dedicated support for manipulating discriminant. Full Zulip thread about the workaround: https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/.E2.9C.94.20Workarounds.20for.20setting.20enum.20discriminants/near/470331454 |
My take: I don't know any other place in the language where we might want to use this kind of syntax, though I can imagine it (e.g., MIR has similar paths of this kind). If we want certainty, though, the only syntax that we can be SURE will not conflict with anything else would be to use pattern matching. Have folks explored pattern matching and what that might look like? I was imagining something like "supply a pattern with exactly one binding" (e.g., |
(Personally though I feel reasonably good about the proposed |
Just confirming what @exrok said - I don't think "set discriminant" functionality should block this FCP, I'm working on a follow-up RFC for that, and that RFC would build on top of this one. Edit: I've opened a PR for this RFC: rust-lang/rfcs#3727 |
Feature gate:
#![feature(offset_of_enum)]
This is a tracking issue for using enum variants in offset_of. Enum variants themselves do not have an offset within their type, so the macro will not give an offset for them, but their fields do. For example, the standard library uses the offset of the content of the
Some
variant ofOption
to implementOption::as_slice
. The original RFC for offset_of was rust-lang/rfcs#3308.Public API
Steps / History
Unresolved Questions
Footnotes
https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html ↩
The text was updated successfully, but these errors were encountered: