Using ~
as the operator syntax for now. I do not like offsetof
as the fundamental operator, because it doesn’t add any safety and unlike pointer::align_offset
this unsafety is mostly not required. But I could imagine an ops::
based design for customization:
/// Encapsulates, safely, a field of `S` with type `T`
struct Field<S, T> { .. }
impl<S, T> Field<S, T> {
unsafe fn offset_ptr(base: *const S) -> *const T;
fn offset(base: &S) -> &T;
// etc. for mut
}
trait std::ops::Traverse<S, T> {
type Output;
unsafe fn traverse(self, field: Field<S, T>) -> Self::Output;
}
The common implementations for that trait could then be done for *const_
, *mut_
, but also as I would imagine on Ref
(!), Pin<P>
, and maybe even exotic pointer types such as Cow
?
impl<S, T> Traverse<S, T> for *const S {
type Output = *const T;
unsafe fn traverse(self, field: Field<S, T>) -> *const T {
field.offset_ptr(self)
}
}
impl<'a, S, T> Traverse<S, T> for &'a S {
type Output = &'a T;
// Note relaxed bound, no unsafe
fn traverse(self, field: Field<S, T>) -> &'a T {
field.offset(self)
}
}
impl<'a, S, T> Traverse<S, T> for Ref<'a, S> {
type Output = Ref<'a, T>;
fn traverse(self, field: Field<S, T>) -> Ref<'a, T>{
self.map(|ptr| field.offset(ptr))
}
}
with the usage:
struct Foobar { member: usize }
let x = RefCell::new(Foobar::default());
let r = x.borrow();
let m = r~member; // Ref<usize>
Similar for Pin
but with some bounds on the impl.
This design has an additional interesting property: One could have associated constants of type Field<Self, T>
to expose some struct attributes without making their names public.