This discussion was started from
But is a bit off topic there, so I started a new thread for it
This is the third edit of this draft, to see previous versions check out the pencil in the top corner
In order to make safe pointer to fields
struct Field<Parent, Type> {
offset: usize
}
which is auto-generated by the compiler like so
struct Foo {
bar: u32,
quaz: i8
}
fn main() {
assert_eq!(Foo::bar, Field::<Foo, u32> { offset: 0 });
assert_eq!(Foo::quaz, Field::<Foo, i8> { offset: 4 }); // (assuming fields aren't reordered by compiler)
}
The syntax for this not important (i.e. Foo::bar
could be changed to something else)
- Another idea for syntax is
Type.field
, this has the benefit of being unambigious
We could then declare it safe to use these fields offsets to project valid pointers to fields like so we could provide something like this
// Always safe to project using this trait given that `self` and `field` are valid
trait Project<FTy> {
type Type;
type Projection;
fn project(self, field: Field<Self::Type, FTy>) -> Self::Projection;
}
impl<T, FTy> *const T {
unsafe fn project_inbounds<FTy>(self, field: Field<T, FTy>) -> *const FTy {
(self as *const _ as *const u8)
.add(field.offset) as *const FTy
}
}
impl<T, FTy> Project<FTy> for *const T {
type Type = T;
type Projection = *const FTy;
fn project(self, field: Field<T, FTy>) -> Self::Projection {
(self as *const _ as *const u8)
.wrapping_add(field.offset) as *const FTy
}
}
impl<'a, T, FTy: 'a> Project<FTy> for &'a T {
type Type = T;
type Projection = &'a FTy;
fn project(self, field: Field<T, FTy>) -> Self::Projection {
unsafe { &*(self as *const _).project_inbounds(field) }
}
}
Which could then be used generically to project to a field.
playground example: