1use proc_macro2::{Delimiter, Group, Span, TokenStream};
4use quote::{format_ident, quote, quote_spanned, ToTokens};
5use syn::{
6 parse_quote, punctuated::Punctuated, token, visit_mut::VisitMut, Attribute, Error, Field,
7 Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Item, Lifetime, LifetimeParam,
8 Meta, Result, Token, Type, Variant, Visibility, WhereClause,
9};
10
11use super::{
12 args::{parse_args, Args, ProjReplace, UnpinImpl},
13 PIN,
14};
15use crate::utils::{
16 determine_lifetime_name, determine_visibility, insert_lifetime_and_bound, ReplaceReceiver,
17 SliceExt, Variants,
18};
19
20pub(super) fn parse_derive(input: TokenStream) -> Result<TokenStream> {
21 let mut input: Item = syn::parse2(input)?;
22
23 let mut cx;
24 let mut generate = GenerateTokens::default();
25
26 match &mut input {
27 Item::Struct(input) => {
28 let ident = &input.ident;
29 let ty_generics = input.generics.split_for_impl().1;
30 let self_ty = parse_quote!(#ident #ty_generics);
31 let mut visitor = ReplaceReceiver(&self_ty);
32 visitor.visit_item_struct_mut(input);
33 cx = Context::new(&input.attrs, &input.vis, &input.ident, &mut input.generics, Struct)?;
34 parse_struct(&mut cx, &input.fields, &mut generate)?;
35 }
36 Item::Enum(input) => {
37 let ident = &input.ident;
38 let ty_generics = input.generics.split_for_impl().1;
39 let self_ty = parse_quote!(#ident #ty_generics);
40 let mut visitor = ReplaceReceiver(&self_ty);
41 visitor.visit_item_enum_mut(input);
42 cx = Context::new(&input.attrs, &input.vis, &input.ident, &mut input.generics, Enum)?;
43 parse_enum(&mut cx, input.brace_token, &input.variants, &mut generate)?;
44 }
45 _ => bail!(input, "#[pin_project] attribute may only be used on structs or enums"),
46 }
47
48 Ok(generate.into_tokens(&cx))
49}
50
51#[derive(Default)]
52struct GenerateTokens {
53 exposed: TokenStream,
54 scoped: TokenStream,
55}
56
57impl GenerateTokens {
58 fn extend(&mut self, expose: bool, tokens: TokenStream) {
59 if expose {
60 self.exposed.extend(tokens);
61 } else {
62 self.scoped.extend(tokens);
63 }
64 }
65
66 fn into_tokens(self, cx: &Context<'_>) -> TokenStream {
67 let mut tokens = self.exposed;
68 let scoped = self.scoped;
69
70 let unpin_impl = make_unpin_impl(cx);
71 let drop_impl = make_drop_impl(cx);
72 let allowed_lints = global_allowed_lints();
73
74 tokens.extend(quote! {
75 #allowed_lints
90 #[allow(unused_qualifications)]
91 #[allow(clippy::needless_lifetimes)]
92 #[allow(clippy::semicolon_if_nothing_returned)]
93 #[allow(clippy::use_self)]
94 #[allow(clippy::used_underscore_binding)]
95 const _: () = {
96 #[allow(unused_extern_crates)]
97 extern crate pin_project as _pin_project;
98 #scoped
99 #unpin_impl
100 #drop_impl
101 };
102 });
103 tokens
104 }
105}
106
107fn global_allowed_lints() -> TokenStream {
109 quote! {
110 #[allow(box_pointers)] #[allow(deprecated)]
112 #[allow(explicit_outlives_requirements)] #[allow(single_use_lifetimes)] #[allow(unreachable_pub)] #[allow(unused_tuple_struct_fields)]
116 #[allow(clippy::unknown_clippy_lints)]
119 #[allow(clippy::pattern_type_mismatch)]
120 #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] }
123}
124
125fn proj_allowed_lints(cx: &Context<'_>) -> (TokenStream, TokenStream, TokenStream) {
127 let large_enum_variant = if cx.kind == Enum {
128 Some(quote! {
129 #[allow(variant_size_differences)]
130 #[allow(clippy::large_enum_variant)]
131 })
132 } else {
133 None
134 };
135 let global_allowed_lints = global_allowed_lints();
136 let proj_mut_allowed_lints = if cx.project { Some(&global_allowed_lints) } else { None };
137 let proj_mut = quote! {
138 #proj_mut_allowed_lints
139 #[allow(dead_code)] #[allow(clippy::mut_mut)] #[allow(clippy::missing_docs_in_private_items)]
142 };
143 let proj_ref_allowed_lints = if cx.project_ref { Some(&global_allowed_lints) } else { None };
144 let proj_ref = quote! {
145 #proj_ref_allowed_lints
146 #[allow(dead_code)] #[allow(clippy::ref_option_ref)] #[allow(clippy::missing_docs_in_private_items)]
149 };
150 let proj_own_allowed_lints =
151 if cx.project_replace.ident().is_some() { Some(&global_allowed_lints) } else { None };
152 let proj_own = quote! {
153 #proj_own_allowed_lints
154 #[allow(dead_code)] #[allow(clippy::missing_docs_in_private_items)]
156 #large_enum_variant
157 };
158 (proj_mut, proj_ref, proj_own)
159}
160
161struct Context<'a> {
162 orig: OriginalType<'a>,
164 proj: ProjectedType,
166 pinned_fields: Vec<&'a Type>,
168 kind: TypeKind,
170
171 pinned_drop: Option<Span>,
173 unpin_impl: UnpinImpl,
175 project: bool,
177 project_ref: bool,
179 project_replace: ProjReplace,
181}
182
183impl<'a> Context<'a> {
184 fn new(
185 attrs: &'a [Attribute],
186 vis: &'a Visibility,
187 ident: &'a Ident,
188 generics: &'a mut Generics,
189 kind: TypeKind,
190 ) -> Result<Self> {
191 let Args { pinned_drop, unpin_impl, project, project_ref, project_replace } =
192 parse_args(attrs)?;
193
194 if let Some(name) = [project.as_ref(), project_ref.as_ref(), project_replace.ident()]
195 .iter()
196 .filter_map(Option::as_ref)
197 .find(|name| **name == ident)
198 {
199 bail!(name, "name `{}` is the same as the original type name", name);
200 }
201
202 let mut lifetime_name = String::from("'pin");
203 determine_lifetime_name(&mut lifetime_name, generics);
204 let lifetime = Lifetime::new(&lifetime_name, Span::call_site());
205
206 let ty_generics = generics.split_for_impl().1;
207 let ty_generics_as_generics = parse_quote!(#ty_generics);
208 let mut proj_generics = generics.clone();
209 let pred = insert_lifetime_and_bound(
210 &mut proj_generics,
211 lifetime.clone(),
212 &ty_generics_as_generics,
213 ident,
214 );
215 let mut where_clause = generics.make_where_clause().clone();
216 where_clause.predicates.push(pred);
217
218 let own_ident = project_replace
219 .ident()
220 .cloned()
221 .unwrap_or_else(|| format_ident!("__{}ProjectionOwned", ident));
222
223 Ok(Self {
224 kind,
225 pinned_drop,
226 unpin_impl,
227 project: project.is_some(),
228 project_ref: project_ref.is_some(),
229 project_replace,
230 proj: ProjectedType {
231 vis: determine_visibility(vis),
232 mut_ident: project.unwrap_or_else(|| format_ident!("__{}Projection", ident)),
233 ref_ident: project_ref.unwrap_or_else(|| format_ident!("__{}ProjectionRef", ident)),
234 own_ident,
235 lifetime,
236 generics: proj_generics,
237 where_clause,
238 },
239 orig: OriginalType { attrs, vis, ident, generics },
240 pinned_fields: vec![],
241 })
242 }
243}
244
245#[derive(Copy, Clone, PartialEq)]
246enum TypeKind {
247 Enum,
248 Struct,
249}
250
251use TypeKind::{Enum, Struct};
252
253struct OriginalType<'a> {
254 attrs: &'a [Attribute],
256 vis: &'a Visibility,
258 ident: &'a Ident,
260 generics: &'a Generics,
262}
263
264struct ProjectedType {
265 vis: Visibility,
267 mut_ident: Ident,
269 ref_ident: Ident,
271 own_ident: Ident,
273 lifetime: Lifetime,
275 generics: Generics,
277 where_clause: WhereClause,
280}
281
282struct ProjectedVariants {
283 proj_variants: TokenStream,
284 proj_ref_variants: TokenStream,
285 proj_own_variants: TokenStream,
286 proj_arms: TokenStream,
287 proj_ref_arms: TokenStream,
288 proj_own_arms: TokenStream,
289}
290
291#[derive(Default)]
292struct ProjectedFields {
293 proj_pat: TokenStream,
294 proj_body: TokenStream,
295 proj_own_body: TokenStream,
296 proj_fields: TokenStream,
297 proj_ref_fields: TokenStream,
298 proj_own_fields: TokenStream,
299}
300
301fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> {
302 if fields.is_empty() {
303 let msg = "#[pin_project] attribute may not be used on structs with zero fields";
304 if let Fields::Unit = fields {
305 bail!(ident, msg)
306 }
307 bail!(fields, msg)
308 }
309 Ok(())
310}
311
312fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
313 if variants.is_empty() {
314 return Err(Error::new(
315 brace_token.span.join(),
316 "#[pin_project] attribute may not be used on enums without variants",
317 ));
318 }
319 let has_field = variants.iter().try_fold(false, |has_field, v| {
320 if let Some((_, e)) = &v.discriminant {
321 bail!(e, "#[pin_project] attribute may not be used on enums with discriminants");
322 } else if let Some(attr) = v.attrs.find(PIN) {
323 bail!(attr, "#[pin] attribute may only be used on fields of structs or variants");
324 } else if v.fields.is_empty() {
325 Ok(has_field)
326 } else {
327 Ok(true)
328 }
329 })?;
330 if has_field {
331 Ok(())
332 } else {
333 bail!(variants, "#[pin_project] attribute may not be used on enums with zero fields");
334 }
335}
336
337fn parse_struct<'a>(
338 cx: &mut Context<'a>,
339 fields: &'a Fields,
340 generate: &mut GenerateTokens,
341) -> Result<()> {
342 let packed_check = ensure_not_packed(&cx.orig, Some(fields))?;
344
345 validate_struct(cx.orig.ident, fields)?;
346
347 let ProjectedFields {
348 proj_pat,
349 proj_body,
350 proj_fields,
351 proj_ref_fields,
352 proj_own_fields,
353 proj_own_body,
354 } = match fields {
355 Fields::Named(_) => visit_fields(cx, None, fields, Delimiter::Brace)?,
356 Fields::Unnamed(_) => visit_fields(cx, None, fields, Delimiter::Parenthesis)?,
357 Fields::Unit => unreachable!(),
358 };
359
360 let proj_ident = &cx.proj.mut_ident;
361 let proj_ref_ident = &cx.proj.ref_ident;
362 let proj_own_ident = &cx.proj.own_ident;
363 let vis = &cx.proj.vis;
364 let mut orig_generics = cx.orig.generics.clone();
365 let orig_where_clause = orig_generics.where_clause.take();
366 let proj_generics = &cx.proj.generics;
367 let proj_where_clause = &cx.proj.where_clause;
368
369 let (where_clause_fields, where_clause_ref_fields, where_clause_own_fields) = match fields {
372 Fields::Named(_) => (
373 quote!(#proj_where_clause #proj_fields),
374 quote!(#proj_where_clause #proj_ref_fields),
375 quote!(#orig_where_clause #proj_own_fields),
376 ),
377 Fields::Unnamed(_) => (
378 quote!(#proj_fields #proj_where_clause;),
379 quote!(#proj_ref_fields #proj_where_clause;),
380 quote!(#proj_own_fields #orig_where_clause;),
381 ),
382 Fields::Unit => unreachable!(),
383 };
384
385 let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx);
386 generate.extend(cx.project, quote! {
387 #proj_attrs
388 #vis struct #proj_ident #proj_generics #where_clause_fields
389 });
390 generate.extend(cx.project_ref, quote! {
391 #proj_ref_attrs
392 #vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields
393 });
394 if cx.project_replace.span().is_some() {
395 generate.extend(cx.project_replace.ident().is_some(), quote! {
396 #proj_own_attrs
397 #vis struct #proj_own_ident #orig_generics #where_clause_own_fields
398 });
399 }
400
401 let proj_mut_body = quote! {
402 let Self #proj_pat = self.get_unchecked_mut();
403 #proj_ident #proj_body
404 };
405 let proj_ref_body = quote! {
406 let Self #proj_pat = self.get_ref();
407 #proj_ref_ident #proj_body
408 };
409 let proj_own_body = quote! {
410 let Self #proj_pat = &mut *__self_ptr;
411 #proj_own_body
412 };
413 generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body));
414
415 generate.extend(false, packed_check);
416 Ok(())
417}
418
419fn parse_enum<'a>(
420 cx: &mut Context<'a>,
421 brace_token: token::Brace,
422 variants: &'a Punctuated<Variant, Token![,]>,
423 generate: &mut GenerateTokens,
424) -> Result<()> {
425 if let ProjReplace::Unnamed { span } = &cx.project_replace {
426 return Err(Error::new(
427 *span,
428 "`project_replace` argument requires a value when used on enums",
429 ));
430 }
431
432 ensure_not_packed(&cx.orig, None)?;
438
439 validate_enum(brace_token, variants)?;
440
441 let ProjectedVariants {
442 proj_variants,
443 proj_ref_variants,
444 proj_own_variants,
445 proj_arms,
446 proj_ref_arms,
447 proj_own_arms,
448 } = visit_variants(cx, variants)?;
449
450 let proj_ident = &cx.proj.mut_ident;
451 let proj_ref_ident = &cx.proj.ref_ident;
452 let proj_own_ident = &cx.proj.own_ident;
453 let vis = &cx.proj.vis;
454 let mut orig_generics = cx.orig.generics.clone();
455 let orig_where_clause = orig_generics.where_clause.take();
456 let proj_generics = &cx.proj.generics;
457 let proj_where_clause = &cx.proj.where_clause;
458
459 let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx);
460 if cx.project {
461 generate.extend(true, quote! {
462 #proj_attrs
463 #vis enum #proj_ident #proj_generics #proj_where_clause {
464 #proj_variants
465 }
466 });
467 }
468 if cx.project_ref {
469 generate.extend(true, quote! {
470 #proj_ref_attrs
471 #vis enum #proj_ref_ident #proj_generics #proj_where_clause {
472 #proj_ref_variants
473 }
474 });
475 }
476 if cx.project_replace.ident().is_some() {
477 generate.extend(true, quote! {
478 #proj_own_attrs
479 #vis enum #proj_own_ident #orig_generics #orig_where_clause {
480 #proj_own_variants
481 }
482 });
483 }
484
485 let proj_mut_body = quote! {
486 match self.get_unchecked_mut() {
487 #proj_arms
488 }
489 };
490 let proj_ref_body = quote! {
491 match self.get_ref() {
492 #proj_ref_arms
493 }
494 };
495 let proj_own_body = quote! {
496 match &mut *__self_ptr {
497 #proj_own_arms
498 }
499 };
500 generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body));
501
502 Ok(())
503}
504
505fn visit_variants<'a>(cx: &mut Context<'a>, variants: &'a Variants) -> Result<ProjectedVariants> {
506 let mut proj_variants = TokenStream::new();
507 let mut proj_ref_variants = TokenStream::new();
508 let mut proj_own_variants = TokenStream::new();
509 let mut proj_arms = TokenStream::new();
510 let mut proj_ref_arms = TokenStream::new();
511 let mut proj_own_arms = TokenStream::new();
512
513 for Variant { ident, fields, .. } in variants {
514 let ProjectedFields {
515 proj_pat,
516 proj_body,
517 proj_fields,
518 proj_ref_fields,
519 proj_own_fields,
520 proj_own_body,
521 } = match fields {
522 Fields::Named(_) => visit_fields(cx, Some(ident), fields, Delimiter::Brace)?,
523 Fields::Unnamed(_) => visit_fields(cx, Some(ident), fields, Delimiter::Parenthesis)?,
524 Fields::Unit => ProjectedFields {
525 proj_own_body: proj_own_body(cx, Some(ident), None, &[]),
526 ..Default::default()
527 },
528 };
529
530 let proj_ident = &cx.proj.mut_ident;
531 let proj_ref_ident = &cx.proj.ref_ident;
532 proj_variants.extend(quote! {
533 #ident #proj_fields,
534 });
535 proj_ref_variants.extend(quote! {
536 #ident #proj_ref_fields,
537 });
538 proj_own_variants.extend(quote! {
539 #ident #proj_own_fields,
540 });
541 proj_arms.extend(quote! {
542 Self::#ident #proj_pat => #proj_ident::#ident #proj_body,
543 });
544 proj_ref_arms.extend(quote! {
545 Self::#ident #proj_pat => #proj_ref_ident::#ident #proj_body,
546 });
547 proj_own_arms.extend(quote! {
548 Self::#ident #proj_pat => { #proj_own_body }
549 });
550 }
551
552 Ok(ProjectedVariants {
553 proj_variants,
554 proj_ref_variants,
555 proj_own_variants,
556 proj_arms,
557 proj_ref_arms,
558 proj_own_arms,
559 })
560}
561
562fn visit_fields<'a>(
563 cx: &mut Context<'a>,
564 variant_ident: Option<&Ident>,
565 fields: &'a Fields,
566 delim: Delimiter,
567) -> Result<ProjectedFields> {
568 fn surround(delim: Delimiter, tokens: TokenStream) -> TokenStream {
569 Group::new(delim, tokens).into_token_stream()
570 }
571
572 let mut proj_pat = TokenStream::new();
573 let mut proj_body = TokenStream::new();
574 let mut proj_fields = TokenStream::new();
575 let mut proj_ref_fields = TokenStream::new();
576 let mut proj_own_fields = TokenStream::new();
577 let mut proj_move = TokenStream::new();
578 let mut pinned_bindings = Vec::with_capacity(fields.len());
579
580 for (i, Field { attrs, vis, ident, colon_token, ty, .. }) in fields.iter().enumerate() {
581 let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}", i));
582 proj_pat.extend(quote!(#binding,));
583 let lifetime = &cx.proj.lifetime;
584 if attrs.position_exact(PIN)?.is_some() {
585 proj_fields.extend(quote! {
586 #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime mut (#ty)>,
587 });
588 proj_ref_fields.extend(quote! {
589 #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime (#ty)>,
590 });
591 proj_own_fields.extend(quote! {
592 #vis #ident #colon_token ::pin_project::__private::PhantomData<#ty>,
593 });
594 proj_body.extend(quote! {
595 #ident #colon_token _pin_project::__private::Pin::new_unchecked(#binding),
596 });
597 proj_move.extend(quote! {
598 #ident #colon_token _pin_project::__private::PhantomData,
599 });
600
601 cx.pinned_fields.push(ty);
602 pinned_bindings.push(binding);
603 } else {
604 proj_fields.extend(quote! {
605 #vis #ident #colon_token &#lifetime mut (#ty),
606 });
607 proj_ref_fields.extend(quote! {
608 #vis #ident #colon_token &#lifetime (#ty),
609 });
610 proj_own_fields.extend(quote! {
611 #vis #ident #colon_token #ty,
612 });
613 proj_body.extend(quote! {
614 #binding,
615 });
616 proj_move.extend(quote! {
617 #ident #colon_token _pin_project::__private::ptr::read(#binding),
618 });
619 }
620 }
621
622 let proj_pat = surround(delim, proj_pat);
623 let proj_body = surround(delim, proj_body);
624 let proj_fields = surround(delim, proj_fields);
625 let proj_ref_fields = surround(delim, proj_ref_fields);
626 let proj_own_fields = surround(delim, proj_own_fields);
627
628 let proj_move = Group::new(delim, proj_move);
629 let proj_own_body = proj_own_body(cx, variant_ident, Some(&proj_move), &pinned_bindings);
630
631 Ok(ProjectedFields {
632 proj_pat,
633 proj_body,
634 proj_own_body,
635 proj_fields,
636 proj_ref_fields,
637 proj_own_fields,
638 })
639}
640
641fn proj_own_body(
645 cx: &Context<'_>,
646 variant_ident: Option<&Ident>,
647 proj_move: Option<&Group>,
648 pinned_fields: &[Ident],
649) -> TokenStream {
650 let ident = &cx.proj.own_ident;
651 let proj_own = match variant_ident {
652 Some(variant_ident) => quote!(#ident::#variant_ident),
653 None => quote!(#ident),
654 };
655
656 let pinned_fields = pinned_fields.iter().rev();
660
661 quote! {
662 let __result = #proj_own #proj_move;
664
665 {
671 #(
672 let __guard = _pin_project::__private::UnsafeDropInPlaceGuard::new(#pinned_fields);
673 )*
674 }
675
676 __result
678 }
679}
680
681fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
688 match cx.unpin_impl {
689 UnpinImpl::Unsafe(span) => {
690 let mut proj_generics = cx.proj.generics.clone();
691 let orig_ident = cx.orig.ident;
692 let lifetime = &cx.proj.lifetime;
693
694 proj_generics.make_where_clause().predicates.push(parse_quote_spanned! { span =>
696 ::pin_project::__private::PinnedFieldsOf<
697 _pin_project::__private::Wrapper<#lifetime, Self>
698 >: _pin_project::UnsafeUnpin
699 });
700
701 let (impl_generics, _, where_clause) = proj_generics.split_for_impl();
702 let ty_generics = cx.orig.generics.split_for_impl().1;
703
704 quote_spanned! { span =>
705 impl #impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics
706 #where_clause
707 {
708 }
709 }
710 }
711 UnpinImpl::Negative(span) => {
712 let mut proj_generics = cx.proj.generics.clone();
713 let orig_ident = cx.orig.ident;
714 let lifetime = &cx.proj.lifetime;
715
716 proj_generics.make_where_clause().predicates.push(parse_quote! {
717 ::pin_project::__private::PinnedFieldsOf<_pin_project::__private::Wrapper<
718 #lifetime, _pin_project::__private::PhantomPinned
719 >>: _pin_project::__private::Unpin
720 });
721
722 let (proj_impl_generics, _, proj_where_clause) = proj_generics.split_for_impl();
723 let ty_generics = cx.orig.generics.split_for_impl().1;
724
725 let unsafety = <Token![unsafe]>::default();
728 quote_spanned! { span =>
729 #[doc(hidden)]
730 impl #proj_impl_generics _pin_project::__private::Unpin
731 for #orig_ident #ty_generics
732 #proj_where_clause
733 {
734 }
735
736 #[doc(hidden)]
743 #unsafety impl #proj_impl_generics _pin_project::UnsafeUnpin
744 for #orig_ident #ty_generics
745 #proj_where_clause
746 {
747 }
748 }
749 }
750 UnpinImpl::Default => {
751 let mut full_where_clause = cx.orig.generics.where_clause.clone().unwrap();
752
753 let fields = cx.pinned_fields.iter().enumerate().map(|(i, ty)| {
756 let field_ident = format_ident!("__field{}", i);
757 quote!(#field_ident: #ty)
758 });
759
760 let lifetime_fields = cx.orig.generics.lifetimes().enumerate().map(
782 |(i, LifetimeParam { lifetime, .. })| {
783 let field_ident = format_ident!("__lifetime{}", i);
784 quote!(#field_ident: &#lifetime ())
785 },
786 );
787
788 let orig_ident = cx.orig.ident;
789 let struct_ident = format_ident!("__{}", orig_ident);
790 let vis = cx.orig.vis;
791 let lifetime = &cx.proj.lifetime;
792 let type_params = cx.orig.generics.type_params().map(|t| &t.ident);
793 let proj_generics = &cx.proj.generics;
794 let (proj_impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl();
795 let (_, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
796
797 full_where_clause.predicates.push(parse_quote! {
798 ::pin_project::__private::PinnedFieldsOf<#struct_ident #proj_ty_generics>:
799 _pin_project::__private::Unpin
800 });
801
802 quote! {
803 #[allow(missing_debug_implementations)]
814 #vis struct #struct_ident #proj_generics #where_clause {
815 __pin_project_use_generics: _pin_project::__private::AlwaysUnpin<
816 #lifetime, (#(_pin_project::__private::PhantomData<#type_params>),*)
817 >,
818
819 #(#fields,)*
820 #(#lifetime_fields,)*
821 }
822
823 impl #proj_impl_generics _pin_project::__private::Unpin
824 for #orig_ident #ty_generics
825 #full_where_clause
826 {
827 }
828
829 #[doc(hidden)]
836 unsafe impl #proj_impl_generics _pin_project::UnsafeUnpin
837 for #orig_ident #ty_generics
838 #full_where_clause
839 {
840 }
841 }
842 }
843 }
844}
845
846fn make_drop_impl(cx: &Context<'_>) -> TokenStream {
853 let ident = cx.orig.ident;
854 let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
855
856 if let Some(span) = cx.pinned_drop {
857 let unsafety = <Token![unsafe]>::default();
860 quote_spanned! { span =>
861 impl #impl_generics _pin_project::__private::Drop for #ident #ty_generics
862 #where_clause
863 {
864 #[allow(clippy::missing_inline_in_public_items)]
865 fn drop(&mut self) {
866 #unsafety {
867 let __pinned_self = _pin_project::__private::Pin::new_unchecked(self);
870 _pin_project::__private::PinnedDrop::drop(__pinned_self);
874 }
875 }
876 }
877 }
878 } else {
879 let trait_ident = format_ident!("{}MustNotImplDrop", ident);
894
895 quote! {
896 trait #trait_ident {}
904 #[allow(clippy::drop_bounds, drop_bounds)]
905 impl<T: _pin_project::__private::Drop> #trait_ident for T {}
906 impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {}
907
908 #[doc(hidden)]
919 impl #impl_generics _pin_project::__private::PinnedDrop for #ident #ty_generics
920 #where_clause
921 {
922 unsafe fn drop(self: _pin_project::__private::Pin<&mut Self>) {}
923 }
924 }
925 }
926}
927
928fn make_proj_impl(
935 cx: &Context<'_>,
936 proj_body: &TokenStream,
937 proj_ref_body: &TokenStream,
938 proj_own_body: &TokenStream,
939) -> TokenStream {
940 let vis = &cx.proj.vis;
941 let lifetime = &cx.proj.lifetime;
942 let orig_ident = cx.orig.ident;
943 let proj_ident = &cx.proj.mut_ident;
944 let proj_ref_ident = &cx.proj.ref_ident;
945 let proj_own_ident = &cx.proj.own_ident;
946
947 let orig_ty_generics = cx.orig.generics.split_for_impl().1;
948 let proj_ty_generics = cx.proj.generics.split_for_impl().1;
949 let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
950 let allow_dead_code = quote! { #[allow(dead_code)] };
955
956 let mut project = Some(quote! {
957 #allow_dead_code
958 #[inline]
959 #vis fn project<#lifetime>(
960 self: _pin_project::__private::Pin<&#lifetime mut Self>,
961 ) -> #proj_ident #proj_ty_generics {
962 unsafe {
963 #proj_body
964 }
965 }
966 });
967 let mut project_ref = Some(quote! {
968 #allow_dead_code
969 #[allow(clippy::missing_const_for_fn)]
970 #[inline]
971 #vis fn project_ref<#lifetime>(
972 self: _pin_project::__private::Pin<&#lifetime Self>,
973 ) -> #proj_ref_ident #proj_ty_generics {
974 unsafe {
975 #proj_ref_body
976 }
977 }
978 });
979 let mut project_replace = cx.project_replace.span().map(|span| {
980 let sig = quote_spanned! { span =>
982 #allow_dead_code
983 #[inline]
984 #vis fn project_replace(
985 self: _pin_project::__private::Pin<&mut Self>,
986 __replacement: Self,
987 ) -> #proj_own_ident #orig_ty_generics
988 };
989 quote! {
990 #sig {
991 unsafe {
992 let __self_ptr: *mut Self = self.get_unchecked_mut();
993
994 let __guard = _pin_project::__private::UnsafeOverwriteGuard::new(
997 __self_ptr,
998 __replacement,
999 );
1000
1001 #proj_own_body
1002 }
1003 }
1004 }
1005 });
1006
1007 if cx.kind == Enum {
1008 if !cx.project {
1009 project = None;
1010 }
1011 if !cx.project_ref {
1012 project_ref = None;
1013 }
1014 if cx.project_replace.ident().is_none() {
1015 project_replace = None;
1016 }
1017 }
1018
1019 quote! {
1020 impl #impl_generics #orig_ident #ty_generics #where_clause {
1021 #project
1022 #project_ref
1023 #project_replace
1024 }
1025 }
1026}
1027
1028fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> {
1035 for attr in orig.attrs {
1036 if let Meta::List(ref list) = attr.meta {
1037 if list.path.is_ident("repr") {
1038 for repr in list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)? {
1039 if repr.path().is_ident("packed") {
1040 let msg = if fields.is_none() {
1041 "#[repr(packed)] attribute should be applied to a struct or union"
1045 } else if repr.require_name_value().is_ok() {
1046 "#[repr(packed)] attribute should not be name-value pair"
1051 } else {
1052 "#[pin_project] attribute may not be used on #[repr(packed)] types"
1053 };
1054 bail!(repr, msg);
1055 }
1056 }
1057 }
1058 }
1059 }
1060
1061 let fields = match fields {
1062 Some(fields) => fields,
1063 None => return Ok(TokenStream::new()),
1064 };
1065
1066 let mut field_refs = vec![];
1113 match fields {
1114 Fields::Named(FieldsNamed { named, .. }) => {
1115 for Field { ident, .. } in named {
1116 field_refs.push(quote!(&this.#ident));
1117 }
1118 }
1119 Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
1120 for (index, _) in unnamed.iter().enumerate() {
1121 let index = Index::from(index);
1122 field_refs.push(quote!(&this.#index));
1123 }
1124 }
1125 Fields::Unit => {}
1126 }
1127
1128 let (impl_generics, ty_generics, where_clause) = orig.generics.split_for_impl();
1129 let ident = orig.ident;
1130 Ok(quote! {
1131 #[forbid(unaligned_references, safe_packed_borrows)]
1132 fn __assert_not_repr_packed #impl_generics (this: &#ident #ty_generics) #where_clause {
1133 #(let _ = #field_refs;)*
1134 }
1135 })
1136}