There is alas no standalone / reliable way to avoid .
-deref operations from occurring when inside a ptr::addr_of{,_mut}!(…)
invocation.
The usual workaround is to be less ambitious w.r.t. projections, and allow the macro to handle them one by one.
From there, by requiring that the intermediary type (your P::Inner
) be specified to the macro as well, the macro can then make the necessary previous checks to make it impossible for the caller to "smuggle" derefs.
In that demo, the syntax I have chosen is:
project!(
& <mut>? <expr> => <P::Inner> => .<field>
)
-
e.g., for a tuple:
project!(&m => (_, _) => .1)
-
and for a (tuple) struct:
project!(&m => StructName<...> => .some_field)
The key idea is that, for (tuple) structs, emitting:
let StructName { field_name: _, .. };
is:
- valid Rust code you can emit anywhere;
- even for numerical/indexed field names!
let Wrapper { 0: _, .. }
.
- even for numerical/indexed field names!
- and which compile-time asserts the existence of
.field_name
for that type, thereby guaranteeing lack of*
-deref shenanigans being involved.
For actual Rust tuples, whilst we cannot do this, it turns out that we do know they do not implement Deref
.
Finally, by emitting the given type in the input arg signature of the closure expected to work with P::Inner
, we are effectively asserting that these two match, so that a ManuallyDrop<& ...>
with thus a P::Inner
of & ...
will correctly reject any of these two usages.