Currently there is no easy and safe way to get a pointer to a field from a pointer to an enum or struct. There has been a lot of talk adding C
like arrow operator ->
which solves the problem:
struct Baz {
a: u32,
b: f32,
}
let baz: *const Baz = /* .. */; // not-a-valid-Baz
// let baz_a: *const u32 = &baz.a as *const u32; // danger! UB
let baz_a: *const u32 = baz->a;
However similar would not work for enums (probably, at least I have not herd of such proposals)
let foo: *const Option<u32> = /* .. */;
let foo_: *const u32 = foo.Some->0; // best I can think of
Feature: Allow pattern-matching of a pointer
This is similar to how &raw [const | mut]
allows taking pointers to fields without going trough an intermediate references.
Dereferencing a ptr
to an enum
let foo: *const Option<u32> = /* .. */;
// the deref of `foo` is unsafe since the tag of the enum must be valid
unsafe {
match *foo {
// new syntax, similar to `&raw [const | mut]` and does not go trough reference
Some(raw ref ptr) => {
let val: &u32 = &*ptr,
},
None => {},
}
}
Dereferencing a ptr
to a struct
let baz: *const Baz = /* .. */; // totally-not-safe-Baz
// the deref of `baz` is safe since we only bind to pointers
match *baz {
Baz {
raw ref a,
raw ref b,
} => {
let a: &u32 = unsafe { *a };
let b: &f32 = unsafe { *b };
}
}
// allow mismatching references and pointers?
// SAFETY:
// foo.b must be valid
unsafe {
match *baz {
Baz {
raw ref a,
ref b,
} => {
let a: &u32 = *a;
let b: &f32 = b;
}
}
}
One of the benefits of this feature is to allow building large structs piece by piece onto the heap
let mut uninit: Box<MaybeUninit<Baz>> = Box::new_uninit();
let ptr: *mut Baz = (&mut *uninit as *mut MaybeUninit<Baz> as *mut Baz);
let Baz { raw ref a, raw ref b } = *ptr;
unsafe {
core::ptr::write(a, 0);
core::ptr::write(b, 0.0);
}
let mut baz = unsafe { baz.assume_init() };
EDIT: Fixed unsafe blocks to make more sense