Skip to content

Commit 31976ee

Browse files
committed
simplify projections and support long-lasting projections
1 parent 5775d14 commit 31976ee

File tree

7 files changed

+101
-154
lines changed

7 files changed

+101
-154
lines changed

examples/kernel_mutex_rcu.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,20 +150,12 @@ impl MyDriver {
150150
cfg.read(rcu_guard).flush_sensitivity
151151
}
152152

153-
/*
154-
* the following implementation of `buffer_config` *should* also compile, but doesn't due to
155-
* the macro having to create a value on the stack...
156-
157153
fn buffer_config<'a>(&'a self, rcu_guard: &'a RcuGuard) -> &'a BufferConfig {
158154
let buf: &'a RcuMutex<Buffer> = &self.buf;
159155
start_proj!(move buf);
160-
//------------------- local binding introduced here
161-
// Here we use the special projections set up for `Mutex` with fields of type `Rcu<T>`.
162-
let cfg: &Rcu<Box<BufferConfig>> = p!(@buf->cfg);
156+
let cfg: &Rcu<Box<BufferConfig>> = p!(@move buf->cfg);
163157
cfg.read(rcu_guard)
164-
//^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
165158
}
166-
*/
167159

168160
fn set_buffer_config(&self, flush_sensitivity: u8) {
169161
// Our `Mutex` pins the value.

internal/src/has_fields.rs

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ fn checker(
185185
fields: &FieldsNamed,
186186
) -> TokenStream {
187187
let proj = format_ident!("__Proj");
188-
let storage = format_ident!("__Storage");
189188
let mut generics = generics.clone();
190189
generics.lt_token.get_or_insert_default();
191190
generics.gt_token.get_or_insert_default();
@@ -196,10 +195,7 @@ fn checker(
196195
0,
197196
parse_quote!(#proj: #compat::ProjectableExt<Inner = #ident #ident_ty_gen>),
198197
);
199-
let (checker_impl_gen, _, _) = generics.split_for_impl();
200-
let mut storage_generics = generics.clone();
201-
storage_generics.params.insert(0, parse_quote!(#storage));
202-
let field_name = fields.named.iter().map(|f| &f.ident).collect::<Vec<_>>();
198+
let (checker_impl_gen, checker_ty_gen, _) = generics.split_for_impl();
203199
let fields = fields.named.iter().map(
204200
|Field {
205201
vis,
@@ -211,77 +207,19 @@ fn checker(
211207
}
212208
},
213209
);
214-
let checker_lt = quote!('___checker);
215-
let (_, storage_ty_gen, _) = storage_generics.split_for_impl();
216-
let mut val_generics = generics.clone();
217-
val_generics.params.insert(0, parse_quote!(#checker_lt));
218-
let (val_impl_gen, _, _) = val_generics.split_for_impl();
219-
let storage_ty_gen = storage_ty_gen.into_token_stream();
220-
let ref_ty_gen: TokenStream = storage_ty_gen
221-
.clone()
222-
.into_iter()
223-
.map(|tt| {
224-
if matches!(&tt, TokenTree::Ident(i) if i == &storage) {
225-
quote!(#compat::RawProjectedRef<#checker_lt, #proj, #ident #ident_ty_gen>)
226-
} else {
227-
quote!(#tt)
228-
}
229-
})
230-
.collect();
231-
let val_ty_gen: TokenStream = storage_ty_gen
232-
.into_iter()
233-
.map(|tt| {
234-
if matches!(&tt, TokenTree::Ident(i) if i == &storage) {
235-
quote!(#compat::RawProjectedVal<#proj, #ident #ident_ty_gen>)
236-
} else {
237-
quote!(#tt)
238-
}
239-
})
240-
.collect();
241210
quote! {
242-
pub struct Checker #storage_generics {
211+
pub struct Checker #generics {
243212
#(#fields,)*
244-
pub ___projection_checker_raw: #storage,
245213
}
246214

247-
unsafe impl #val_impl_gen #compat::ProjectionRefChecker<#checker_lt> for Checker #ref_ty_gen {
215+
unsafe impl #checker_impl_gen #compat::ProjectionChecker for Checker #checker_ty_gen {
248216
type Proj = #proj;
249-
250-
unsafe fn __create(
251-
proj: #compat::RawProjectedRef<
252-
#checker_lt,
253-
Self::Proj,
254-
<Self::Proj as #core_::ops::Projectable>::Inner,
255-
>,
256-
) -> Self {
257-
Self {
258-
#(#field_name: unsafe { #compat::ProjectedField::__new() },)*
259-
___projection_checker_raw: proj,
260-
}
261-
}
262-
}
263-
264-
unsafe impl #checker_impl_gen #compat::ProjectionValChecker for Checker #val_ty_gen {
265-
type Proj = #proj;
266-
267-
unsafe fn __create(
268-
proj: #compat::RawProjectedVal<
269-
Self::Proj,
270-
<Self::Proj as #core_::ops::Projectable>::Inner,
271-
>,
272-
) -> Self {
273-
Self {
274-
#(#field_name: unsafe { #compat::ProjectedField::__new() },)*
275-
___projection_checker_raw: proj,
276-
}
277-
}
278217
}
279218

280219
unsafe impl #checker_impl_gen #compat::CheckedProject<#proj> for #ident #ident_ty_gen
281220
#whr
282221
{
283-
type RefChecker<#checker_lt> = Checker #ref_ty_gen;
284-
type ValChecker = Checker #val_ty_gen;
222+
type Checker = Checker #checker_ty_gen;
285223
}
286224
}
287225
}

internal/src/project.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use proc_macro2::TokenStream;
22
use quote::{ToTokens, format_ident, quote, quote_spanned};
33
use syn::{Member, Result, Token, parse::Parse, spanned::Spanned};
44

5-
use crate::IdentOrSelf;
5+
use crate::{IdentOrSelf, start::ProjKind};
66

77
pub struct Input {
88
at: Token![@],
9+
move_: Option<Token![move]>,
910
mut_: Option<Token![mut]>,
1011
base: IdentOrSelf,
1112
arrow: Token![->],
@@ -15,6 +16,7 @@ pub struct Input {
1516
impl ToTokens for Input {
1617
fn to_tokens(&self, tokens: &mut TokenStream) {
1718
self.at.to_tokens(tokens);
19+
self.move_.to_tokens(tokens);
1820
self.mut_.to_tokens(tokens);
1921
self.base.to_tokens(tokens);
2022
self.arrow.to_tokens(tokens);
@@ -26,6 +28,7 @@ impl Parse for Input {
2628
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
2729
let res = Self {
2830
at: input.parse()?,
31+
move_: input.parse()?,
2932
mut_: input.parse()?,
3033
base: input.parse()?,
3134
arrow: input.parse()?,
@@ -41,24 +44,28 @@ impl Parse for Input {
4144
pub fn expand(input: Input) -> Result<TokenStream> {
4245
let span = input.span();
4346
let Input {
47+
move_,
4448
mut_,
4549
base: IdentOrSelf(base),
4650
field,
4751
..
4852
} = input;
49-
let base = format_ident!("___projections_for_{base}");
53+
let raw_ = format_ident!("___projections_raw_ptr_for_{base}");
54+
let base = format_ident!("___projections_checker_for_{base}");
5055
let compat = quote!(::field_projection::compat);
51-
let (project, access) = match &mut_ {
52-
Some(_) => (quote!(project_mut), quote!(access_mut)),
53-
None => (quote!(project), quote!(access)),
56+
let (action, deref, project) = match &(move_, mut_) {
57+
(Some(_), Some(_)) => (quote!(), quote!(), quote!(project_move_mut)),
58+
(Some(_), None) => (quote!(), quote!(), quote!(project_move)),
59+
(None, Some(mut_)) => (quote!(&#mut_), quote!(*), quote!(project_mut)),
60+
(None, None) => (quote!(&), quote!(*), quote!(project)),
5461
};
5562
Ok(quote_spanned! {span=>
5663
match (
57-
&#mut_ #base.#field,
58-
#compat::RawProjectionAccess::#access(&#mut_ #base.___projection_checker_raw),
64+
#action #base.#field,
65+
#raw_
5966
) {
6067
(this, raw) => {
61-
#compat::ProjectedField::safety_check(&*this).check();
68+
#compat::ProjectedField::safety_check(& #deref this).check();
6269
#[allow(unused_unsafe)]
6370
let res = unsafe {
6471
#compat::ProjectedField::#project(

internal/src/start.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use proc_macro2::TokenStream;
2-
use quote::{format_ident, quote};
2+
use quote::{ToTokens, format_ident, quote};
33
use syn::{Expr, Result, Token, parse::Parse};
44

55
use crate::IdentOrSelf;
@@ -9,10 +9,9 @@ pub struct Input {
99
name: IdentOrSelf,
1010
}
1111

12-
enum ProjKind {
12+
pub enum ProjKind {
1313
Shared,
1414
Mut(Token![mut]),
15-
#[expect(dead_code)]
1615
Move(Token![move]),
1716
}
1817

@@ -28,6 +27,16 @@ impl Parse for ProjKind {
2827
}
2928
}
3029

30+
impl ToTokens for ProjKind {
31+
fn to_tokens(&self, tokens: &mut TokenStream) {
32+
match self {
33+
ProjKind::Shared => {}
34+
ProjKind::Mut(mut_) => mut_.to_tokens(tokens),
35+
ProjKind::Move(move_) => move_.to_tokens(tokens),
36+
}
37+
}
38+
}
39+
3140
impl Parse for Input {
3241
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
3342
let res = Self {
@@ -47,13 +56,19 @@ pub fn expand(
4756
name: IdentOrSelf(name),
4857
}: Input,
4958
) -> TokenStream {
50-
let projections = format_ident!("___projections_for_{name}");
59+
let projections = format_ident!("___projections_checker_for_{name}");
60+
let raw_ = format_ident!("___projections_raw_ptr_for_{name}");
5161
let (start, mut_, action) = match &kind {
52-
ProjKind::Move(_) => (quote!(__start_proj_move), quote!(mut), quote!()),
62+
ProjKind::Move(_) => (quote!(__start_proj_move), quote!(), quote!()),
5363
ProjKind::Mut(mut_) => (quote!(__start_proj_mut), quote!(#mut_), quote!(&#mut_)),
5464
ProjKind::Shared => (quote!(__start_proj), quote!(), quote!(&)),
5565
};
66+
let (rest, raw_mut) = match &kind {
67+
ProjKind::Move(_) => (quote!(let #raw_ = &raw mut #raw_;), quote!(mut)),
68+
_ => (quote!(), quote!()),
69+
};
5670
quote! {
57-
let #mut_ #projections = ::field_projection::compat::#start(#action #name);
71+
let (#mut_ #projections, #raw_mut #raw_) = ::field_projection::compat::#start(#action #name);
72+
#rest
5873
}
5974
}

src/compat.rs

Lines changed: 17 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -47,53 +47,35 @@ impl Unsafe {
4747
}
4848

4949
pub unsafe trait CheckedProject<P: ProjectableExt> {
50-
type RefChecker<'a>: ProjectionRefChecker<'a, Proj = P>;
51-
type ValChecker: ProjectionValChecker<Proj = P>;
50+
type Checker: ProjectionChecker<Proj = P>;
5251
}
5352

54-
pub unsafe trait ProjectionRefChecker<'a> {
53+
pub unsafe trait ProjectionChecker {
5554
type Proj: ProjectableExt<Inner: CheckedProject<Self::Proj>>;
56-
57-
unsafe fn __create(
58-
proj: RawProjectedRef<'a, Self::Proj, <Self::Proj as Projectable>::Inner>,
59-
) -> Self;
60-
}
61-
62-
pub unsafe trait ProjectionValChecker {
63-
type Proj: ProjectableExt<Inner: CheckedProject<Self::Proj>>;
64-
65-
unsafe fn __create(
66-
proj: RawProjectedVal<Self::Proj, <Self::Proj as Projectable>::Inner>,
67-
) -> Self;
6855
}
6956

70-
pub fn __start_proj<'a, P>(proj: &'a P) -> <P::Inner as CheckedProject<P>>::RefChecker<'a>
57+
pub fn __start_proj<P>(proj: &P) -> (&<P::Inner as CheckedProject<P>>::Checker, *const P)
7158
where
7259
P: ProjectableExt,
7360
P::Inner: CheckedProject<P>,
7461
{
75-
let ptr: *const P = proj;
76-
let proj = RawProjectedRef(ptr, PhantomData);
77-
unsafe { <P::Inner as CheckedProject<P>>::RefChecker::__create(proj) }
62+
(unsafe { core::mem::transmute(&()) }, proj)
7863
}
7964

80-
pub fn __start_proj_mut<'a, P>(proj: &'a mut P) -> <P::Inner as CheckedProject<P>>::RefChecker<'a>
65+
pub fn __start_proj_mut<P>(proj: &mut P) -> (&mut <P::Inner as CheckedProject<P>>::Checker, *mut P)
8166
where
8267
P: ProjectableExt,
8368
P::Inner: CheckedProject<P>,
8469
{
85-
let ptr: *mut P = proj;
86-
let proj = RawProjectedRef(ptr, PhantomData);
87-
unsafe { <P::Inner as CheckedProject<P>>::RefChecker::__create(proj) }
70+
(unsafe { core::mem::transmute(&mut ()) }, proj)
8871
}
8972

90-
pub fn __start_proj_move<P>(proj: P) -> <P::Inner as CheckedProject<P>>::ValChecker
73+
pub fn __start_proj_move<P>(proj: P) -> (<P::Inner as CheckedProject<P>>::Checker, P)
9174
where
9275
P: ProjectableExt,
9376
P::Inner: CheckedProject<P>,
9477
{
95-
let proj = RawProjectedVal(proj, PhantomData);
96-
unsafe { <P::Inner as CheckedProject<P>>::ValChecker::__create(proj) }
78+
(unsafe { core::mem::transmute_copy(&()) }, proj)
9779
}
9880

9981
pub struct ProjectedField<P, F>(PhantomData<P>, PhantomData<F>);
@@ -111,54 +93,24 @@ where
11193
Default::default()
11294
}
11395

114-
pub unsafe fn project<'a>(
115-
self: &'a ProjectedField<P, F>,
116-
raw: RawProjectedPtr<P>,
117-
) -> <P as Project<F>>::Output<'a>
96+
pub unsafe fn project<'a>(&'a self, raw: *const P) -> <P as Project<F>>::Output<'a>
11897
where
11998
P: Project<F>,
12099
{
121-
unsafe { <P as Project<F>>::project(raw.0) }
100+
unsafe { <P as Project<F>>::project(raw) }
122101
}
123102

124-
pub unsafe fn project_mut<'a>(
125-
self: &'a mut ProjectedField<P, F>,
126-
raw: RawProjectedPtr<P>,
127-
) -> <P as ProjectMut<F>>::OutputMut<'a>
103+
pub unsafe fn project_mut<'a>(&'a mut self, raw: *mut P) -> <P as ProjectMut<F>>::OutputMut<'a>
128104
where
129105
P: ProjectMut<F>,
130106
{
131-
unsafe { <P as ProjectMut<F>>::project_mut(raw.0.cast_mut()) }
107+
unsafe { <P as ProjectMut<F>>::project_mut(raw) }
132108
}
133-
}
134-
135-
pub struct RawProjectedPtr<P>(*const P);
136-
137-
pub struct RawProjectedRef<'a, P, T: ?Sized>(*const P, PhantomData<(&'a (), &'a mut (), P, T)>);
138-
139-
pub struct RawProjectedVal<P, T: ?Sized>(P, PhantomData<(P, T)>);
140-
141-
pub trait RawProjectionAccess<P> {
142-
fn access(&self) -> RawProjectedPtr<P>;
143-
fn access_mut(&mut self) -> RawProjectedPtr<P>;
144-
}
145109

146-
impl<'a, P, T: ?Sized> RawProjectionAccess<P> for RawProjectedRef<'a, P, T> {
147-
fn access(&self) -> RawProjectedPtr<P> {
148-
RawProjectedPtr(self.0)
149-
}
150-
151-
fn access_mut(&mut self) -> RawProjectedPtr<P> {
152-
RawProjectedPtr(self.0)
153-
}
154-
}
155-
156-
impl<P, T: ?Sized> RawProjectionAccess<P> for RawProjectedVal<P, T> {
157-
fn access(&self) -> RawProjectedPtr<P> {
158-
RawProjectedPtr(&raw const self.0)
159-
}
160-
161-
fn access_mut(&mut self) -> RawProjectedPtr<P> {
162-
RawProjectedPtr(&raw mut self.0)
110+
pub unsafe fn project_move<'a>(self, raw: *const P) -> <P as Project<F>>::Output<'a>
111+
where
112+
P: Project<F>,
113+
{
114+
unsafe { <P as Project<F>>::project(raw) }
163115
}
164116
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use field_projection::compat::{HasFields, start_proj};
2+
3+
#[derive(HasFields)]
4+
#[fields(with_pinned)]
5+
pub struct Foo {
6+
a: usize,
7+
}
8+
9+
impl Foo {
10+
pub fn new() -> Self {
11+
Self { a: 42 }
12+
}
13+
}
14+
15+
fn main() {
16+
let mut foo = Box::pin(Foo::new());
17+
let mut foo = foo.as_mut();
18+
start_proj!(mut foo);
19+
// sadly we can access these
20+
let _: () = ___projections_raw_ptr_for_foo;
21+
let _: () = ___projections_checker_for_foo;
22+
}

0 commit comments

Comments
 (0)