rust: pin-init: internal: pin_data: complete invariant borrow support

Non-covariant types can already be accessed inside projections. As
projections are only generated for `Pin<&mut T>`, they're not accessible
otherwise. Add `with_{field_name}` methods so fields can be accessed using
closures with just `&T`.

Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-17-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
This commit is contained in:
Gary Guo 2026-05-02 22:40:15 +01:00
parent 91a255fea7
commit e55acb7337
2 changed files with 30 additions and 1 deletions

View File

@ -6,6 +6,9 @@
#[pin_data]
struct SelfRef {
#[uses('_: invariant)]
not_cov: Box<dyn Fn(&'str str) -> bool + 'str>,
part: &'str str,
str: String,
@ -20,6 +23,7 @@ fn use_self_ref() {
part: &str[..5],
mut_str: "hello world".to_owned(),
mut_part: &mut mut_str[..5],
not_cov: Box::new(move |s| s == str),
}));
// Access via projection.
@ -41,6 +45,14 @@ fn use_self_ref() {
foo.as_mut().with_project(|proj| {
proj.mut_part.make_ascii_uppercase();
});
// Access non-covariant type using `with_` accessor.
foo.with_not_cov(|not_cov| {
not_cov("");
});
// Access non-covariant type using `with_project`.
foo.as_mut().with_project(|proj| (proj.not_cov)(proj.str));
}
fn main() {

View File

@ -1441,7 +1441,24 @@ fn generate_projections(info: &StructInfo) -> TokenStream {
}
))
} else {
continue;
let f_doc = format!("Access the `{ident}` field on a shared reference of `Self`.");
let vis = &f.field.vis;
let with_ident = format_ident!("with_{ident}");
let all_lifetimes: Vec<_> = f.captures.iter().map(|b| &b.lifetime).collect();
let ty = &f.field.ty;
accessors.push(quote!(
#[doc = #f_doc]
#[inline]
#vis fn #with_ident<'__this, R>(
&'__this self,
f: impl for<#(#all_lifetimes,)*> ::core::ops::FnOnce(&'__this #ty) -> R,
) -> R {
// SAFETY: we have `Erase<..>` which we know is layout compatible with `f.ty`.
f(unsafe { ::core::mem::transmute(&self.#member) })
}
))
}
}