Skip to content

Commit 5775d14

Browse files
committed
allow usage of value after start_proj which is now a macro
1 parent b967bda commit 5775d14

18 files changed

+289
-99
lines changed

examples/custom_arc.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ impl<T> Deref for Arc<T> {
1616
type Target = T;
1717

1818
fn deref(&self) -> &Self::Target {
19-
let inner = start_proj(self.inner);
19+
let inner = self.inner;
20+
start_proj!(inner);
2021
let value = unsafe { p!(@inner->value) };
2122
unsafe { value.as_ref() }
2223
}

examples/fair_race_future.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ where
1919
{
2020
type Output = F1::Output;
2121

22-
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
23-
let mut this = start_proj(self);
24-
let fair: &mut bool = p!(@mut this->fair);
22+
fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
23+
start_proj!(mut self);
24+
let fair: &mut bool = p!(@mut self->fair);
2525
*fair = !*fair;
26-
match *p!(@this->fair) {
26+
match *p!(@self->fair) {
2727
true => {
28-
let f1: Pin<&mut F1> = p!(@mut this->f1);
28+
let f1: Pin<&mut F1> = p!(@mut self->f1);
2929
match f1.poll(cx) {
30-
Poll::Pending => p!(@mut this->f2).poll(cx),
30+
Poll::Pending => p!(@mut self->f2).poll(cx),
3131
Poll::Ready(val) => Poll::Ready(val),
3232
}
3333
}
34-
false => match p!(@mut this->f2).poll(cx) {
35-
Poll::Pending => p!(@mut this->f1).poll(cx),
34+
false => match p!(@mut self->f2).poll(cx) {
35+
Poll::Pending => p!(@mut self->f1).poll(cx),
3636
Poll::Ready(val) => Poll::Ready(val),
3737
},
3838
}

examples/initializing.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ struct VeryBig {
1313
}
1414

1515
impl VeryBig {
16-
pub fn init(this: &mut MaybeUninit<Self>) {
17-
let mut this = start_proj(this);
16+
pub fn init(mut this: &mut MaybeUninit<Self>) {
17+
start_proj!(mut this);
1818
p!(@mut this->a).write(42);
1919
p!(@mut this->b).write(0);
2020
p!(@mut this->buf).as_bytes_mut().write_filled(0xef);

examples/kernel_mutex_rcu.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ struct MyDriver {
143143

144144
impl MyDriver {
145145
fn flush_sensitivity<'a>(&'a self, rcu_guard: &'a RcuGuard) -> u8 {
146-
let buf = start_proj(&self.buf);
146+
let buf = &self.buf;
147+
start_proj!(buf);
147148
// Here we use the special projections set up for `Mutex` with fields of type `Rcu<T>`.
148149
let cfg: &Rcu<Box<BufferConfig>> = p!(@buf->cfg);
149150
cfg.read(rcu_guard).flush_sensitivity
@@ -154,20 +155,21 @@ impl MyDriver {
154155
* the macro having to create a value on the stack...
155156
156157
fn buffer_config<'a>(&'a self, rcu_guard: &'a RcuGuard) -> &'a BufferConfig {
157-
let buf = start_proj(&self.buf);
158+
let buf: &'a RcuMutex<Buffer> = &self.buf;
159+
start_proj!(move buf);
160+
//------------------- local binding introduced here
158161
// Here we use the special projections set up for `Mutex` with fields of type `Rcu<T>`.
159162
let cfg: &Rcu<Box<BufferConfig>> = p!(@buf->cfg);
160-
// --------- `buf.cfg` is borrowed here
161163
cfg.read(rcu_guard)
162164
//^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
163165
}
164-
165-
*/
166+
*/
166167

167168
fn set_buffer_config(&self, flush_sensitivity: u8) {
168169
// Our `Mutex` pins the value.
169170
let mut guard: Pin<RcuMutexGuard<'_, Buffer>> = self.buf.lock();
170-
let mut buf = start_proj(guard.as_mut());
171+
let mut buf = guard.as_mut();
172+
start_proj!(mut buf);
171173
// We can use pin-projections since we marked `cfg` as `#[pin]`
172174
let cfg: Pin<&mut Rcu<Box<BufferConfig>>> = p!(@mut buf->cfg);
173175
cfg.set(Box::new(BufferConfig { flush_sensitivity }));

examples/kernel_ptr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ where
4141
where
4242
Self: 'b,
4343
{
44-
let this = start_proj(this);
44+
start_proj!(this);
4545
let ptr = unsafe { *p!(@this->inner) };
4646
Ptr {
4747
inner: unsafe { ptr.byte_add(F::OFFSET).cast() },

internal/src/has_fields.rs

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -185,49 +185,103 @@ fn checker(
185185
fields: &FieldsNamed,
186186
) -> TokenStream {
187187
let proj = format_ident!("__Proj");
188-
let (_, ty_gen, _) = generics.split_for_impl();
188+
let storage = format_ident!("__Storage");
189189
let mut generics = generics.clone();
190190
generics.lt_token.get_or_insert_default();
191191
generics.gt_token.get_or_insert_default();
192+
let (_, ident_ty_gen, whr) = generics.split_for_impl();
193+
let mut generics = generics.clone();
192194
// TODO: proper index
193195
generics.params.insert(
194196
0,
195-
parse_quote!(#proj: #compat::ProjectableExt<Inner = #ident #ty_gen>),
197+
parse_quote!(#proj: #compat::ProjectableExt<Inner = #ident #ident_ty_gen>),
196198
);
197-
let field_name = fields.named.iter().map(|f| &f.ident);
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<_>>();
198203
let fields = fields.named.iter().map(
199204
|Field {
200205
vis,
201206
ident: name,
202207
..
203208
}| {
204209
quote! {
205-
#vis #name: #compat::ProjectedField<#proj, #core_::marker::field_of!(#ident #ty_gen, #name)>
210+
#vis #name: #compat::ProjectedField<#proj, #core_::marker::field_of!(#ident #ident_ty_gen, #name)>
206211
}
207212
},
208213
);
209-
let (impl_gen, checker_ty_gen, whr) = generics.split_for_impl();
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();
210241
quote! {
211-
pub struct Checker #generics {
242+
pub struct Checker #storage_generics {
212243
#(#fields,)*
213-
pub ___projection_checker_raw: #compat::RawProjected<#proj, #ident #ty_gen>,
244+
pub ___projection_checker_raw: #storage,
245+
}
246+
247+
unsafe impl #val_impl_gen #compat::ProjectionRefChecker<#checker_lt> for Checker #ref_ty_gen {
248+
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+
}
214262
}
215263

216-
unsafe impl #impl_gen #compat::ProjectionChecker for Checker #checker_ty_gen {
264+
unsafe impl #checker_impl_gen #compat::ProjectionValChecker for Checker #val_ty_gen {
217265
type Proj = #proj;
218266

219-
fn start_proj(proj: Self::Proj) -> Self {
267+
unsafe fn __create(
268+
proj: #compat::RawProjectedVal<
269+
Self::Proj,
270+
<Self::Proj as #core_::ops::Projectable>::Inner,
271+
>,
272+
) -> Self {
220273
Self {
221274
#(#field_name: unsafe { #compat::ProjectedField::__new() },)*
222-
___projection_checker_raw: unsafe { #compat::RawProjected::__new(proj) },
275+
___projection_checker_raw: proj,
223276
}
224277
}
225278
}
226279

227-
unsafe impl #impl_gen #compat::CheckedProject<#proj> for #ident #ty_gen
280+
unsafe impl #checker_impl_gen #compat::CheckedProject<#proj> for #ident #ident_ty_gen
228281
#whr
229282
{
230-
type Checker = Checker #checker_ty_gen;
283+
type RefChecker<#checker_lt> = Checker #ref_ty_gen;
284+
type ValChecker = Checker #val_ty_gen;
231285
}
232286
}
233287
}

internal/src/lib.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use proc_macro::TokenStream;
2-
use syn::{DeriveInput, parse_macro_input};
2+
use quote::ToTokens;
3+
use syn::{DeriveInput, Ident, Token, parse::Parse, parse_macro_input};
34

45
mod has_fields;
56
mod project;
7+
mod start;
68

79
#[proc_macro]
810
pub fn p(input: TokenStream) -> TokenStream {
@@ -11,9 +13,33 @@ pub fn p(input: TokenStream) -> TokenStream {
1113
.into()
1214
}
1315

16+
#[proc_macro]
17+
pub fn start_proj(input: TokenStream) -> TokenStream {
18+
start::expand(parse_macro_input!(input as _)).into()
19+
}
20+
1421
#[proc_macro_derive(HasFields, attributes(fields, pin))]
1522
pub fn derive_has_fields(item: TokenStream) -> TokenStream {
1623
has_fields::derive(parse_macro_input!(item as DeriveInput))
1724
.unwrap_or_else(|e| e.into_compile_error())
1825
.into()
1926
}
27+
28+
struct IdentOrSelf(Ident);
29+
30+
impl Parse for IdentOrSelf {
31+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
32+
if input.peek(Token![self]) {
33+
let self_: Token![self] = input.parse()?;
34+
Ok(Self(Ident::new("self", self_.span)))
35+
} else {
36+
input.parse().map(Self)
37+
}
38+
}
39+
}
40+
41+
impl ToTokens for IdentOrSelf {
42+
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
43+
self.0.to_tokens(tokens)
44+
}
45+
}

internal/src/project.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
use proc_macro2::{TokenStream, TokenTree};
2-
use quote::{ToTokens, quote, quote_spanned};
3-
use syn::{Ident, Member, Result, Token, parse::Parse, spanned::Spanned};
1+
use proc_macro2::TokenStream;
2+
use quote::{ToTokens, format_ident, quote, quote_spanned};
3+
use syn::{Member, Result, Token, parse::Parse, spanned::Spanned};
4+
5+
use crate::IdentOrSelf;
46

57
pub struct Input {
68
at: Token![@],
7-
mutability: Option<Token![mut]>,
8-
base: Ident,
9+
mut_: Option<Token![mut]>,
10+
base: IdentOrSelf,
911
arrow: Token![->],
1012
field: Member,
1113
}
1214

1315
impl ToTokens for Input {
1416
fn to_tokens(&self, tokens: &mut TokenStream) {
1517
self.at.to_tokens(tokens);
16-
self.mutability.to_tokens(tokens);
18+
self.mut_.to_tokens(tokens);
1719
self.base.to_tokens(tokens);
1820
self.arrow.to_tokens(tokens);
1921
self.field.to_tokens(tokens);
@@ -24,7 +26,7 @@ impl Parse for Input {
2426
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
2527
let res = Self {
2628
at: input.parse()?,
27-
mutability: input.parse()?,
29+
mut_: input.parse()?,
2830
base: input.parse()?,
2931
arrow: input.parse()?,
3032
field: input.parse()?,
@@ -39,20 +41,21 @@ impl Parse for Input {
3941
pub fn expand(input: Input) -> Result<TokenStream> {
4042
let span = input.span();
4143
let Input {
42-
mutability,
43-
base,
44+
mut_,
45+
base: IdentOrSelf(base),
4446
field,
4547
..
4648
} = input;
49+
let base = format_ident!("___projections_for_{base}");
4750
let compat = quote!(::field_projection::compat);
48-
let (project, access) = match &mutability {
51+
let (project, access) = match &mut_ {
4952
Some(_) => (quote!(project_mut), quote!(access_mut)),
5053
None => (quote!(project), quote!(access)),
5154
};
5255
Ok(quote_spanned! {span=>
5356
match (
54-
&#mutability #base.#field,
55-
#compat::RawProjected::#access(&#mutability #base.___projection_checker_raw),
57+
&#mut_ #base.#field,
58+
#compat::RawProjectionAccess::#access(&#mut_ #base.___projection_checker_raw),
5659
) {
5760
(this, raw) => {
5861
#compat::ProjectedField::safety_check(&*this).check();

internal/src/start.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use proc_macro2::TokenStream;
2+
use quote::{format_ident, quote};
3+
use syn::{Expr, Result, Token, parse::Parse};
4+
5+
use crate::IdentOrSelf;
6+
7+
pub struct Input {
8+
kind: ProjKind,
9+
name: IdentOrSelf,
10+
}
11+
12+
enum ProjKind {
13+
Shared,
14+
Mut(Token![mut]),
15+
#[expect(dead_code)]
16+
Move(Token![move]),
17+
}
18+
19+
impl Parse for ProjKind {
20+
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
21+
if input.peek(Token![mut]) {
22+
input.parse().map(Self::Mut)
23+
} else if input.peek(Token![move]) {
24+
input.parse().map(Self::Move)
25+
} else {
26+
Ok(Self::Shared)
27+
}
28+
}
29+
}
30+
31+
impl Parse for Input {
32+
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
33+
let res = Self {
34+
kind: input.parse()?,
35+
name: input.parse()?,
36+
};
37+
if !input.is_empty() {
38+
return Err(input.error("unexpected tokens"));
39+
}
40+
Ok(res)
41+
}
42+
}
43+
44+
pub fn expand(
45+
Input {
46+
kind,
47+
name: IdentOrSelf(name),
48+
}: Input,
49+
) -> TokenStream {
50+
let projections = format_ident!("___projections_for_{name}");
51+
let (start, mut_, action) = match &kind {
52+
ProjKind::Move(_) => (quote!(__start_proj_move), quote!(mut), quote!()),
53+
ProjKind::Mut(mut_) => (quote!(__start_proj_mut), quote!(#mut_), quote!(&#mut_)),
54+
ProjKind::Shared => (quote!(__start_proj), quote!(), quote!(&)),
55+
};
56+
quote! {
57+
let #mut_ #projections = ::field_projection::compat::#start(#action #name);
58+
}
59+
}

0 commit comments

Comments
 (0)