Skip to content

Commit 68e783d

Browse files
bors[bot]taiki-e
andauthored
94: Remove "project_attr" feature and always enable #[project] attribute r=taiki-e a=taiki-e Closes taiki-e#82 96: Determine the visibility based on the original type r=taiki-e a=taiki-e The visibility of the projected type and projection method is based on the original type. However, if the visibility of the original type is `pub`, the visibility of the projected type and the projection method is `pub(crate)`. Closes taiki-e#81 Co-authored-by: Taiki Endo <te316e89@gmail.com>
3 parents b6d8141 + 3462ea4 + 65944b8 commit 68e783d

File tree

13 files changed

+112
-56
lines changed

13 files changed

+112
-56
lines changed

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ all-features = true
1818
members = ["pin-project-internal"]
1919

2020
[features]
21-
# Enable to use `project` attribute.
22-
project_attr = ["pin-project-internal/project_attr"]
2321
# Enable to allow using this crate as a renamed dependency
2422
renamed = ["pin-project-internal/renamed"]
2523

examples/pinned_drop-expanded.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ pub struct Foo<'a, T> {
3333

3434
#[allow(clippy::mut_mut)]
3535
#[allow(dead_code)]
36-
struct __FooProjection<'_pin, 'a, T> {
36+
pub(crate) struct __FooProjection<'_pin, 'a, T> {
3737
was_dropped: &'_pin mut &'a mut bool,
3838
field: ::core::pin::Pin<&'_pin mut T>,
3939
}
4040

4141
impl<'a, T> Foo<'a, T> {
42-
fn project<'_pin>(self: ::core::pin::Pin<&'_pin mut Self>) -> __FooProjection<'_pin, 'a, T> {
42+
pub(crate) fn project<'_pin>(
43+
self: ::core::pin::Pin<&'_pin mut Self>,
44+
) -> __FooProjection<'_pin, 'a, T> {
4345
unsafe {
4446
let Foo { was_dropped, field } = self.get_unchecked_mut();
4547
__FooProjection {

examples/unsafe_unpin-expanded.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ pub struct Foo<T, U> {
2828

2929
#[allow(clippy::mut_mut)]
3030
#[allow(dead_code)]
31-
struct __FooProjection<'_pin, T, U> {
31+
pub(crate) struct __FooProjection<'_pin, T, U> {
3232
pinned: ::core::pin::Pin<&'_pin mut T>,
3333
unpinned: &'_pin mut U,
3434
}
3535

3636
impl<T, U> Foo<T, U> {
37-
fn project<'_pin>(self: ::core::pin::Pin<&'_pin mut Self>) -> __FooProjection<'_pin, T, U> {
37+
pub(crate) fn project<'_pin>(
38+
self: ::core::pin::Pin<&'_pin mut Self>,
39+
) -> __FooProjection<'_pin, T, U> {
3840
unsafe {
3941
let Foo { pinned, unpinned } = self.get_unchecked_mut();
4042
__FooProjection { pinned: ::core::pin::Pin::new_unchecked(pinned), unpinned: unpinned }

pin-project-internal/Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,13 @@ all-features = true
1717
proc-macro = true
1818

1919
[features]
20-
# Enable to use `project` attribute.
21-
project_attr = ["syn/visit-mut"]
2220
# Enable to allow using the crate with a renamed 'pin-project' dependency
2321
renamed = ["proc-macro-crate", "serde", "lazy_static"]
2422

2523
[dependencies]
2624
proc-macro2 = "1.0"
2725
quote = "1.0"
28-
syn = { version = "1.0", features = ["full"] }
26+
syn = { version = "1.0", features = ["full", "visit-mut"] }
2927

3028
proc-macro-crate = { version = "0.1.4", optional = true }
3129
# Required until a new toml-rs release is made with https://github.com/alexcrichton/toml-rs/pull/311,

pin-project-internal/src/lib.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ mod utils;
1919

2020
mod pin_project;
2121
mod pinned_drop;
22-
#[cfg(feature = "project_attr")]
2322
mod project;
2423

2524
use proc_macro::TokenStream;
@@ -45,6 +44,10 @@ use syn::parse::Nothing;
4544
/// # }
4645
/// ```
4746
///
47+
/// The visibility of the projected type and projection method is based on the
48+
/// original type. However, if the visibility of the original type is `pub`,
49+
/// the visibility of the projected type and the projection method is `pub(crate)`.
50+
///
4851
/// If you want to call the `project` method multiple times or later use the
4952
/// original Pin type, it needs to use [`.as_mut()`][`Pin::as_mut`] to avoid
5053
/// consuming the `Pin`.
@@ -265,30 +268,23 @@ use syn::parse::Nothing;
265268
///
266269
/// ### Enums
267270
///
268-
/// `pin_project` also supports enums, but to use it ergonomically, you need
269-
/// to use the [`project`] attribute.
270-
///
271-
/// *This attribute is only available if pin-project is built
272-
/// with the `"project_attr"` feature.*
271+
/// `pin_project` also supports enums, but to use it, you need to use with the
272+
/// [`project`] attribute.
273273
///
274274
/// The attribute at the expression position is not stable, so you need to use
275275
/// a dummy `#[project]` attribute for the function.
276276
///
277277
/// ```rust
278-
/// # #[cfg(feature = "project_attr")]
279278
/// use pin_project::{project, pin_project};
280-
/// # #[cfg(feature = "project_attr")]
281279
/// use std::pin::Pin;
282280
///
283-
/// # #[cfg(feature = "project_attr")]
284281
/// #[pin_project]
285282
/// enum Foo<A, B, C> {
286283
/// Tuple(#[pin] A, B),
287284
/// Struct { field: C },
288285
/// Unit,
289286
/// }
290287
///
291-
/// # #[cfg(feature = "project_attr")]
292288
/// impl<A, B, C> Foo<A, B, C> {
293289
/// #[project] // Nightly does not need a dummy attribute to the function.
294290
/// fn baz(self: Pin<&mut Self>) {
@@ -368,9 +364,6 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
368364
// TODO: Move this doc into pin-project crate when https://github.com/rust-lang/rust/pull/62855 merged.
369365
/// An attribute to provide way to refer to the projected type.
370366
///
371-
/// *This attribute is available if pin-project is built with the
372-
/// `"project_attr"` feature.*
373-
///
374367
/// The following three syntaxes are supported.
375368
///
376369
/// ## `impl` blocks
@@ -479,7 +472,6 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
479472
/// }
480473
/// }
481474
/// ```
482-
#[cfg(feature = "project_attr")]
483475
#[proc_macro_attribute]
484476
pub fn project(args: TokenStream, input: TokenStream) -> TokenStream {
485477
let _: Nothing = syn::parse_macro_input!(args);

pin-project-internal/src/pin_project/attribute.rs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use syn::{
77
};
88

99
use crate::utils::{
10-
self, collect_cfg, crate_path, proj_ident, proj_lifetime_name, VecExt, DEFAULT_LIFETIME_NAME,
10+
self, collect_cfg, crate_path, determine_visibility, proj_ident, proj_lifetime_name, VecExt,
11+
DEFAULT_LIFETIME_NAME,
1112
};
1213

1314
use super::PIN;
@@ -16,15 +17,15 @@ pub(super) fn parse_attribute(args: TokenStream, mut item: Item) -> Result<Token
1617
let cx;
1718
let proj_items = match &mut item {
1819
Item::Struct(item) => {
19-
cx = Context::new(args, &mut item.attrs, &item.ident, &item.generics)?;
20+
cx = Context::new(args, &mut item.attrs, &item.ident, &item.vis, &item.generics)?;
2021

2122
let packed_check = ensure_not_packed(&item)?;
2223
let mut proj_items = cx.parse_struct(item)?;
2324
proj_items.extend(packed_check);
2425
proj_items
2526
}
2627
Item::Enum(item) => {
27-
cx = Context::new(args, &mut item.attrs, &item.ident, &item.generics)?;
28+
cx = Context::new(args, &mut item.attrs, &item.ident, &item.vis, &item.generics)?;
2829

2930
// We don't need to check for '#[repr(packed)]',
3031
// since it does not apply to enums.
@@ -96,6 +97,9 @@ struct Context {
9697
/// Name of the projected type.
9798
proj_ident: Ident,
9899

100+
/// Visibility of the original type.
101+
vis: Visibility,
102+
99103
/// Generics of the original type.
100104
generics: Generics,
101105

@@ -114,6 +118,7 @@ impl Context {
114118
args: TokenStream,
115119
attrs: &mut Vec<Attribute>,
116120
orig_ident: &Ident,
121+
vis: &Visibility,
117122
generics: &Generics,
118123
) -> Result<Self> {
119124
let Args { pinned_drop, unsafe_unpin } = syn::parse2(args)?;
@@ -133,6 +138,7 @@ impl Context {
133138
crate_path,
134139
orig_ident: orig_ident.clone(),
135140
proj_ident: proj_ident(orig_ident),
141+
vis: determine_visibility(vis),
136142
generics: generics.clone(),
137143
lifetime,
138144
unsafe_unpin,
@@ -258,7 +264,7 @@ impl Context {
258264

259265
/// Creates an implementation of the projection method.
260266
fn make_proj_impl(&self, proj_body: &TokenStream) -> TokenStream {
261-
let Context { proj_ident, orig_ident, lifetime, .. } = &self;
267+
let Context { proj_ident, orig_ident, vis, lifetime, .. } = self;
262268

263269
let proj_generics = self.proj_generics();
264270
let proj_ty_generics = proj_generics.split_for_impl().1;
@@ -267,7 +273,7 @@ impl Context {
267273

268274
quote! {
269275
impl #impl_generics #orig_ident #ty_generics #where_clause {
270-
fn project<#lifetime>(
276+
#vis fn project<#lifetime>(
271277
self: ::core::pin::Pin<&#lifetime mut Self>,
272278
) -> #proj_ident #proj_ty_generics {
273279
unsafe {
@@ -385,14 +391,14 @@ impl Context {
385391
Fields::Unit => unreachable!(),
386392
};
387393

388-
let Context { orig_ident, proj_ident, .. } = &self;
394+
let Context { orig_ident, proj_ident, vis, .. } = self;
389395
let proj_generics = self.proj_generics();
390396
let where_clause = item.generics.split_for_impl().2;
391397

392398
let mut proj_items = quote! {
393399
#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
394400
#[allow(dead_code)] // This lint warns unused fields/variants.
395-
struct #proj_ident #proj_generics #where_clause #proj_fields
401+
#vis struct #proj_ident #proj_generics #where_clause #proj_fields
396402
};
397403

398404
let proj_body = quote! {
@@ -410,14 +416,14 @@ impl Context {
410416

411417
let (proj_variants, proj_arms) = self.visit_variants(item)?;
412418

413-
let proj_ident = &self.proj_ident;
419+
let Context { proj_ident, vis, .. } = &self;
414420
let proj_generics = self.proj_generics();
415421
let where_clause = item.generics.split_for_impl().2;
416422

417423
let mut proj_items = quote! {
418424
#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
419425
#[allow(dead_code)] // This lint warns unused fields/variants.
420-
enum #proj_ident #proj_generics #where_clause {
426+
#vis enum #proj_ident #proj_generics #where_clause {
421427
#(#proj_variants,)*
422428
}
423429
};
@@ -466,13 +472,13 @@ impl Context {
466472
let mut proj_pat = Vec::with_capacity(fields.len());
467473
let mut proj_body = Vec::with_capacity(fields.len());
468474
let mut proj_fields = Vec::with_capacity(fields.len());
469-
for Field { attrs, ident, ty, .. } in fields {
475+
for Field { attrs, vis, ident, ty, .. } in fields {
470476
let cfg = collect_cfg(attrs);
471477
if self.find_pin_attr(attrs)? {
472478
let lifetime = &self.lifetime;
473479
proj_fields.push(quote! {
474480
#(#cfg)*
475-
#ident: ::core::pin::Pin<&#lifetime mut #ty>
481+
#vis #ident: ::core::pin::Pin<&#lifetime mut #ty>
476482
});
477483
proj_body.push(quote! {
478484
#(#cfg)*
@@ -482,7 +488,7 @@ impl Context {
482488
let lifetime = &self.lifetime;
483489
proj_fields.push(quote! {
484490
#(#cfg)*
485-
#ident: &#lifetime mut #ty
491+
#vis #ident: &#lifetime mut #ty
486492
});
487493
proj_body.push(quote! {
488494
#(#cfg)*
@@ -508,7 +514,7 @@ impl Context {
508514
let mut proj_pat = Vec::with_capacity(fields.len());
509515
let mut proj_body = Vec::with_capacity(fields.len());
510516
let mut proj_fields = Vec::with_capacity(fields.len());
511-
for (i, Field { attrs, ty, .. }) in fields.iter_mut().enumerate() {
517+
for (i, Field { attrs, vis, ty, .. }) in fields.iter_mut().enumerate() {
512518
let id = format_ident!("_x{}", i);
513519
let cfg = collect_cfg(attrs);
514520
if !cfg.is_empty() {
@@ -521,15 +527,15 @@ impl Context {
521527
if self.find_pin_attr(attrs)? {
522528
let lifetime = &self.lifetime;
523529
proj_fields.push(quote! {
524-
::core::pin::Pin<&#lifetime mut #ty>
530+
#vis ::core::pin::Pin<&#lifetime mut #ty>
525531
});
526532
proj_body.push(quote! {
527533
::core::pin::Pin::new_unchecked(#id)
528534
});
529535
} else {
530536
let lifetime = &self.lifetime;
531537
proj_fields.push(quote! {
532-
&#lifetime mut #ty
538+
#vis &#lifetime mut #ty
533539
});
534540
proj_body.push(quote! {
535541
#id

pin-project-internal/src/utils.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use quote::format_ident;
1+
use quote::{format_ident, quote_spanned};
22
use syn::{
33
punctuated::Punctuated,
44
token::{self, Comma},
@@ -12,7 +12,7 @@ pub(crate) fn proj_ident(ident: &Ident) -> Ident {
1212
format_ident!("__{}Projection", ident)
1313
}
1414

15-
/// Determine the lifetime names. Ensure it doesn't overlap with any existing lifetime names.
15+
/// Determines the lifetime names. Ensure it doesn't overlap with any existing lifetime names.
1616
pub(crate) fn proj_lifetime_name(
1717
lifetime_name: &mut String,
1818
generics: &Punctuated<GenericParam, Comma>,
@@ -52,6 +52,18 @@ pub(crate) fn proj_generics(generics: &mut Generics, lifetime: Lifetime) {
5252
);
5353
}
5454

55+
/// Determines the visibility of the projected type and projection method.
56+
pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility {
57+
if let Visibility::Public(token) = vis {
58+
syn::parse2(quote_spanned! { token.pub_token.span =>
59+
pub(crate)
60+
})
61+
.unwrap()
62+
} else {
63+
vis.clone()
64+
}
65+
}
66+
5567
pub(crate) fn collect_cfg(attrs: &[Attribute]) -> Vec<Attribute> {
5668
attrs.iter().filter(|attr| attr.path.is_ident("cfg")).cloned().collect()
5769
}

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ pub use pin_project_internal::pin_project;
5757
#[doc(hidden)]
5858
pub use pin_project_internal::pinned_drop;
5959

60-
#[cfg(feature = "project_attr")]
6160
#[doc(hidden)]
6261
pub use pin_project_internal::project;
6362

tests/compiletest.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![cfg(compiletest)]
22
#![cfg(pin_project_show_unpin_struct)]
3-
#![cfg(feature = "project_attr")]
43
#![warn(rust_2018_idioms, single_use_lifetimes)]
54

65
use std::{env, path::PathBuf};

tests/pin_project.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,6 @@ fn combine() {
240240
unsafe impl<T: Unpin> UnsafeUnpin for Foo<T> {}
241241
}
242242

243-
// This 'allow' is unrelated to the code
244-
// generated by pin-project - it's just to
245-
// allow us to put a private enum in a public enum
246-
#[allow(private_in_public)]
247243
#[test]
248244
fn private_type_in_public_type() {
249245
#[pin_project]
@@ -253,15 +249,6 @@ fn private_type_in_public_type() {
253249
}
254250

255251
struct PrivateStruct<T>(T);
256-
257-
#[pin_project]
258-
pub enum PublicEnum {
259-
Variant(#[pin] PrivateEnum),
260-
}
261-
262-
enum PrivateEnum {
263-
OtherVariant(u8),
264-
}
265252
}
266253

267254
#[test]
@@ -320,3 +307,19 @@ fn lifetime_project() {
320307
}
321308
}
322309
}
310+
311+
mod visibility {
312+
use pin_project::pin_project;
313+
314+
#[pin_project]
315+
pub(crate) struct A {
316+
pub b: u8,
317+
}
318+
}
319+
320+
#[test]
321+
fn visibility() {
322+
let mut x = visibility::A { b: 0 };
323+
let x = Pin::new(&mut x).project();
324+
let _: &mut u8 = x.b;
325+
}

0 commit comments

Comments
 (0)