1use proc_macro2::{Delimiter, Group, Span, TokenStream};
4use quote::{ToTokens as _, format_ident, quote, quote_spanned};
5use syn::{
6 Attribute, Error, Field, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Item,
7 Lifetime, LifetimeParam, Meta, Result, Token, Type, Variant, Visibility, WhereClause,
8 parse_quote, punctuated::Punctuated, token, visit_mut::VisitMut as _,
9};
10
11use super::{
12 PIN,
13 args::{Args, ProjReplace, UnpinImpl, parse_args},
14};
15use crate::utils::{
16 ReplaceReceiver, SliceExt as _, Variants, determine_lifetime_name, determine_visibility,
17 insert_lifetime_and_bound,
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 #[allow(
90 unused_qualifications,
91 #allowed_lints
92 clippy::elidable_lifetime_names,
93 clippy::missing_const_for_fn,
94 clippy::needless_lifetimes,
95 clippy::semicolon_if_nothing_returned,
96 clippy::use_self,
97 clippy::used_underscore_binding
98 )]
99 const _: () = {
100 #[allow(unused_extern_crates)]
101 extern crate pin_project as _pin_project;
102 #scoped
103 #unpin_impl
104 #drop_impl
105 };
106 });
107 tokens
108 }
109}
110
111fn global_allowed_lints() -> TokenStream {
113 quote! {
114 deprecated,
115 explicit_outlives_requirements, single_use_lifetimes, unreachable_pub, unused_tuple_struct_fields,
119 clippy::unknown_clippy_lints,
122 clippy::absolute_paths,
123 clippy::min_ident_chars,
124 clippy::pattern_type_mismatch,
125 clippy::pub_with_shorthand,
126 clippy::redundant_pub_crate, clippy::single_char_lifetime_names,
128 clippy::type_repetition_in_bounds, }
130}
131
132fn proj_allowed_lints(cx: &Context<'_>) -> (TokenStream, TokenStream, TokenStream) {
134 let global_allowed_lints = global_allowed_lints();
135 let proj_mut_allowed_lints = if cx.project { Some(&global_allowed_lints) } else { None };
136 let proj_mut = quote! {
137 #[allow(
138 dead_code, #proj_mut_allowed_lints
140 clippy::missing_docs_in_private_items,
141 clippy::mut_mut )]
143 };
144 let proj_ref_allowed_lints = if cx.project_ref { Some(&global_allowed_lints) } else { None };
145 let proj_ref = quote! {
146 #[allow(
147 dead_code, #proj_ref_allowed_lints
149 clippy::missing_docs_in_private_items,
150 clippy::ref_option_ref )]
152 };
153 let proj_own_allowed_lints =
154 if cx.project_replace.ident().is_some() { Some(&global_allowed_lints) } else { None };
155 let variant_size_differences = if cx.kind == Enum {
156 Some(quote! { variant_size_differences, clippy::large_enum_variant, })
157 } else {
158 None
159 };
160 let proj_own = quote! {
161 #[allow(
162 dead_code, #proj_own_allowed_lints
164 #variant_size_differences
165 clippy::missing_docs_in_private_items
166 )]
167 };
168 (proj_mut, proj_ref, proj_own)
169}
170
171struct Context<'a> {
172 orig: OriginalType<'a>,
174 proj: ProjectedType,
176 pinned_fields: Vec<&'a Type>,
178 kind: TypeKind,
180
181 pinned_drop: Option<Span>,
183 unpin_impl: UnpinImpl,
185 project: bool,
187 project_ref: bool,
189 project_replace: ProjReplace,
191}
192
193impl<'a> Context<'a> {
194 fn new(
195 attrs: &'a [Attribute],
196 vis: &'a Visibility,
197 ident: &'a Ident,
198 generics: &'a mut Generics,
199 kind: TypeKind,
200 ) -> Result<Self> {
201 let Args { pinned_drop, unpin_impl, project, project_ref, project_replace } =
202 parse_args(attrs)?;
203
204 if let Some(name) = [project.as_ref(), project_ref.as_ref(), project_replace.ident()]
205 .iter()
206 .filter_map(Option::as_ref)
207 .find(|name| **name == ident)
208 {
209 bail!(name, "name `{}` is the same as the original type name", name);
210 }
211
212 let mut lifetime_name = String::from("'pin");
213 determine_lifetime_name(&mut lifetime_name, generics);
214 let lifetime = Lifetime::new(&lifetime_name, Span::call_site());
215
216 let ty_generics = generics.split_for_impl().1;
217 let ty_generics_as_generics = parse_quote!(#ty_generics);
218 let mut proj_generics = generics.clone();
219 let pred = insert_lifetime_and_bound(
220 &mut proj_generics,
221 lifetime.clone(),
222 &ty_generics_as_generics,
223 ident,
224 );
225 let mut where_clause = generics.make_where_clause().clone();
226 where_clause.predicates.push(pred);
227
228 let own_ident = project_replace
229 .ident()
230 .cloned()
231 .unwrap_or_else(|| format_ident!("__{}ProjectionOwned", ident));
232
233 Ok(Self {
234 kind,
235 pinned_drop,
236 unpin_impl,
237 project: project.is_some(),
238 project_ref: project_ref.is_some(),
239 project_replace,
240 proj: ProjectedType {
241 vis: determine_visibility(vis),
242 mut_ident: project.unwrap_or_else(|| format_ident!("__{}Projection", ident)),
243 ref_ident: project_ref.unwrap_or_else(|| format_ident!("__{}ProjectionRef", ident)),
244 own_ident,
245 lifetime,
246 generics: proj_generics,
247 where_clause,
248 },
249 orig: OriginalType { attrs, vis, ident, generics },
250 pinned_fields: vec![],
251 })
252 }
253}
254
255#[derive(Copy, Clone, PartialEq)]
256enum TypeKind {
257 Enum,
258 Struct,
259}
260use self::TypeKind::{Enum, Struct};
261
262struct OriginalType<'a> {
263 attrs: &'a [Attribute],
265 vis: &'a Visibility,
267 ident: &'a Ident,
269 generics: &'a Generics,
271}
272
273struct ProjectedType {
274 vis: Visibility,
276 mut_ident: Ident,
278 ref_ident: Ident,
280 own_ident: Ident,
282 lifetime: Lifetime,
284 generics: Generics,
286 where_clause: WhereClause,
289}
290
291struct ProjectedVariants {
292 proj_variants: TokenStream,
293 proj_ref_variants: TokenStream,
294 proj_own_variants: TokenStream,
295 proj_arms: TokenStream,
296 proj_ref_arms: TokenStream,
297 proj_own_arms: TokenStream,
298}
299
300#[derive(Default)]
301struct ProjectedFields {
302 proj_pat: TokenStream,
303 proj_body: TokenStream,
304 proj_own_body: TokenStream,
305 proj_fields: TokenStream,
306 proj_ref_fields: TokenStream,
307 proj_own_fields: TokenStream,
308}
309
310fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> {
311 if fields.is_empty() {
312 let msg = "#[pin_project] attribute may not be used on structs with zero fields";
313 if let Fields::Unit = fields {
314 bail!(ident, msg)
315 }
316 bail!(fields, msg)
317 }
318 Ok(())
319}
320
321fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
322 if variants.is_empty() {
323 return Err(Error::new(
324 brace_token.span.join(),
325 "#[pin_project] attribute may not be used on enums without variants",
326 ));
327 }
328 let has_field = variants.iter().try_fold(false, |has_field, v| {
329 if let Some((_, e)) = &v.discriminant {
330 bail!(e, "#[pin_project] attribute may not be used on enums with discriminants");
331 } else if let Some(attr) = v.attrs.find(PIN) {
332 bail!(attr, "#[pin] attribute may only be used on fields of structs or variants");
333 } else if v.fields.is_empty() {
334 Ok(has_field)
335 } else {
336 Ok(true)
337 }
338 })?;
339 if has_field {
340 Ok(())
341 } else {
342 bail!(variants, "#[pin_project] attribute may not be used on enums with zero fields");
343 }
344}
345
346fn parse_struct<'a>(
347 cx: &mut Context<'a>,
348 fields: &'a Fields,
349 generate: &mut GenerateTokens,
350) -> Result<()> {
351 let packed_check = ensure_not_packed(&cx.orig, Some(fields))?;
353
354 validate_struct(cx.orig.ident, fields)?;
355
356 let ProjectedFields {
357 proj_pat,
358 proj_body,
359 proj_fields,
360 proj_ref_fields,
361 proj_own_fields,
362 proj_own_body,
363 } = match fields {
364 Fields::Named(_) => visit_fields(cx, None, fields, Delimiter::Brace)?,
365 Fields::Unnamed(_) => visit_fields(cx, None, fields, Delimiter::Parenthesis)?,
366 Fields::Unit => unreachable!(),
367 };
368
369 let proj_ident = &cx.proj.mut_ident;
370 let proj_ref_ident = &cx.proj.ref_ident;
371 let proj_own_ident = &cx.proj.own_ident;
372 let vis = &cx.proj.vis;
373 let mut orig_generics = cx.orig.generics.clone();
374 let orig_where_clause = orig_generics.where_clause.take();
375 let proj_generics = &cx.proj.generics;
376 let proj_where_clause = &cx.proj.where_clause;
377
378 let (where_clause_fields, where_clause_ref_fields, where_clause_own_fields) = match fields {
381 Fields::Named(_) => (
382 quote!(#proj_where_clause #proj_fields),
383 quote!(#proj_where_clause #proj_ref_fields),
384 quote!(#orig_where_clause #proj_own_fields),
385 ),
386 Fields::Unnamed(_) => (
387 quote!(#proj_fields #proj_where_clause;),
388 quote!(#proj_ref_fields #proj_where_clause;),
389 quote!(#proj_own_fields #orig_where_clause;),
390 ),
391 Fields::Unit => unreachable!(),
392 };
393
394 let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx);
395 generate.extend(cx.project, quote! {
396 #proj_attrs
397 #vis struct #proj_ident #proj_generics #where_clause_fields
398 });
399 generate.extend(cx.project_ref, quote! {
400 #proj_ref_attrs
401 #vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields
402 });
403 if cx.project_replace.span().is_some() {
404 generate.extend(cx.project_replace.ident().is_some(), quote! {
405 #proj_own_attrs
406 #vis struct #proj_own_ident #orig_generics #where_clause_own_fields
407 });
408 }
409
410 let proj_mut_body = quote! {
411 let Self #proj_pat = self.get_unchecked_mut();
412 #proj_ident #proj_body
413 };
414 let proj_ref_body = quote! {
415 let Self #proj_pat = self.get_ref();
416 #proj_ref_ident #proj_body
417 };
418 let proj_own_body = quote! {
419 let Self #proj_pat = &mut *__self_ptr;
420 #proj_own_body
421 };
422 generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body));
423
424 generate.extend(false, packed_check);
425 Ok(())
426}
427
428fn parse_enum<'a>(
429 cx: &mut Context<'a>,
430 brace_token: token::Brace,
431 variants: &'a Punctuated<Variant, Token![,]>,
432 generate: &mut GenerateTokens,
433) -> Result<()> {
434 if let ProjReplace::Unnamed { span } = &cx.project_replace {
435 return Err(Error::new(
436 *span,
437 "`project_replace` argument requires a value when used on enums",
438 ));
439 }
440
441 ensure_not_packed(&cx.orig, None)?;
447
448 validate_enum(brace_token, variants)?;
449
450 let ProjectedVariants {
451 proj_variants,
452 proj_ref_variants,
453 proj_own_variants,
454 proj_arms,
455 proj_ref_arms,
456 proj_own_arms,
457 } = visit_variants(cx, variants)?;
458
459 let proj_ident = &cx.proj.mut_ident;
460 let proj_ref_ident = &cx.proj.ref_ident;
461 let proj_own_ident = &cx.proj.own_ident;
462 let vis = &cx.proj.vis;
463 let mut orig_generics = cx.orig.generics.clone();
464 let orig_where_clause = orig_generics.where_clause.take();
465 let proj_generics = &cx.proj.generics;
466 let proj_where_clause = &cx.proj.where_clause;
467
468 let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx);
469 if cx.project {
470 generate.extend(true, quote! {
471 #proj_attrs
472 #vis enum #proj_ident #proj_generics #proj_where_clause {
473 #proj_variants
474 }
475 });
476 }
477 if cx.project_ref {
478 generate.extend(true, quote! {
479 #proj_ref_attrs
480 #vis enum #proj_ref_ident #proj_generics #proj_where_clause {
481 #proj_ref_variants
482 }
483 });
484 }
485 if cx.project_replace.ident().is_some() {
486 generate.extend(true, quote! {
487 #proj_own_attrs
488 #vis enum #proj_own_ident #orig_generics #orig_where_clause {
489 #proj_own_variants
490 }
491 });
492 }
493
494 let proj_mut_body = quote! {
495 match self.get_unchecked_mut() {
496 #proj_arms
497 }
498 };
499 let proj_ref_body = quote! {
500 match self.get_ref() {
501 #proj_ref_arms
502 }
503 };
504 let proj_own_body = quote! {
505 match &mut *__self_ptr {
506 #proj_own_arms
507 }
508 };
509 generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body));
510
511 Ok(())
512}
513
514fn visit_variants<'a>(cx: &mut Context<'a>, variants: &'a Variants) -> Result<ProjectedVariants> {
515 let mut proj_variants = TokenStream::new();
516 let mut proj_ref_variants = TokenStream::new();
517 let mut proj_own_variants = TokenStream::new();
518 let mut proj_arms = TokenStream::new();
519 let mut proj_ref_arms = TokenStream::new();
520 let mut proj_own_arms = TokenStream::new();
521
522 for Variant { ident, fields, .. } in variants {
523 let ProjectedFields {
524 proj_pat,
525 proj_body,
526 proj_fields,
527 proj_ref_fields,
528 proj_own_fields,
529 proj_own_body,
530 } = match fields {
531 Fields::Named(_) => visit_fields(cx, Some(ident), fields, Delimiter::Brace)?,
532 Fields::Unnamed(_) => visit_fields(cx, Some(ident), fields, Delimiter::Parenthesis)?,
533 Fields::Unit => ProjectedFields {
534 proj_own_body: proj_own_body(cx, Some(ident), None, &[]),
535 ..Default::default()
536 },
537 };
538
539 let proj_ident = &cx.proj.mut_ident;
540 let proj_ref_ident = &cx.proj.ref_ident;
541 proj_variants.extend(quote! {
542 #ident #proj_fields,
543 });
544 proj_ref_variants.extend(quote! {
545 #ident #proj_ref_fields,
546 });
547 proj_own_variants.extend(quote! {
548 #ident #proj_own_fields,
549 });
550 proj_arms.extend(quote! {
551 Self::#ident #proj_pat => #proj_ident::#ident #proj_body,
552 });
553 proj_ref_arms.extend(quote! {
554 Self::#ident #proj_pat => #proj_ref_ident::#ident #proj_body,
555 });
556 proj_own_arms.extend(quote! {
557 Self::#ident #proj_pat => { #proj_own_body }
558 });
559 }
560
561 Ok(ProjectedVariants {
562 proj_variants,
563 proj_ref_variants,
564 proj_own_variants,
565 proj_arms,
566 proj_ref_arms,
567 proj_own_arms,
568 })
569}
570
571fn visit_fields<'a>(
572 cx: &mut Context<'a>,
573 variant_ident: Option<&Ident>,
574 fields: &'a Fields,
575 delim: Delimiter,
576) -> Result<ProjectedFields> {
577 fn surround(delim: Delimiter, tokens: TokenStream) -> TokenStream {
578 Group::new(delim, tokens).into_token_stream()
579 }
580
581 let mut proj_pat = TokenStream::new();
582 let mut proj_body = TokenStream::new();
583 let mut proj_fields = TokenStream::new();
584 let mut proj_ref_fields = TokenStream::new();
585 let mut proj_own_fields = TokenStream::new();
586 let mut proj_move = TokenStream::new();
587 let mut pinned_bindings = Vec::with_capacity(fields.len());
588
589 for (i, Field { attrs, vis, ident, colon_token, ty, .. }) in fields.iter().enumerate() {
590 let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}", i));
591 proj_pat.extend(quote!(#binding,));
592 let lifetime = &cx.proj.lifetime;
593 if attrs.position_exact(PIN)?.is_some() {
594 proj_fields.extend(quote! {
595 #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime mut (#ty)>,
596 });
597 proj_ref_fields.extend(quote! {
598 #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime (#ty)>,
599 });
600 proj_own_fields.extend(quote! {
601 #vis #ident #colon_token ::pin_project::__private::PhantomData<#ty>,
602 });
603 proj_body.extend(quote! {
604 #ident #colon_token _pin_project::__private::Pin::new_unchecked(#binding),
605 });
606 proj_move.extend(quote! {
607 #ident #colon_token _pin_project::__private::PhantomData,
608 });
609
610 cx.pinned_fields.push(ty);
611 pinned_bindings.push(binding);
612 } else {
613 proj_fields.extend(quote! {
614 #vis #ident #colon_token &#lifetime mut (#ty),
615 });
616 proj_ref_fields.extend(quote! {
617 #vis #ident #colon_token &#lifetime (#ty),
618 });
619 proj_own_fields.extend(quote! {
620 #vis #ident #colon_token #ty,
621 });
622 proj_body.extend(quote! {
623 #binding,
624 });
625 proj_move.extend(quote! {
626 #ident #colon_token _pin_project::__private::ptr::read(#binding),
627 });
628 }
629 }
630
631 let proj_pat = surround(delim, proj_pat);
632 let proj_body = surround(delim, proj_body);
633 let proj_fields = surround(delim, proj_fields);
634 let proj_ref_fields = surround(delim, proj_ref_fields);
635 let proj_own_fields = surround(delim, proj_own_fields);
636
637 let proj_move = Group::new(delim, proj_move);
638 let proj_own_body = proj_own_body(cx, variant_ident, Some(&proj_move), &pinned_bindings);
639
640 Ok(ProjectedFields {
641 proj_pat,
642 proj_body,
643 proj_own_body,
644 proj_fields,
645 proj_ref_fields,
646 proj_own_fields,
647 })
648}
649
650fn proj_own_body(
654 cx: &Context<'_>,
655 variant_ident: Option<&Ident>,
656 proj_move: Option<&Group>,
657 pinned_fields: &[Ident],
658) -> TokenStream {
659 let ident = &cx.proj.own_ident;
660 let proj_own = match variant_ident {
661 Some(variant_ident) => quote!(#ident::#variant_ident),
662 None => quote!(#ident),
663 };
664
665 let pinned_fields = pinned_fields.iter().rev();
669
670 quote! {
671 let __result = #proj_own #proj_move;
673
674 {
680 #(
681 let __guard = _pin_project::__private::UnsafeDropInPlaceGuard::new(#pinned_fields);
682 )*
683 }
684
685 __result
687 }
688}
689
690fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
697 match cx.unpin_impl {
698 UnpinImpl::Unsafe(span) => {
699 let mut proj_generics = cx.proj.generics.clone();
700 let orig_ident = cx.orig.ident;
701 let lifetime = &cx.proj.lifetime;
702
703 proj_generics.make_where_clause().predicates.push(parse_quote_spanned! { span =>
705 _pin_project::__private::PinnedFieldsOf<
706 _pin_project::__private::Wrapper<#lifetime, Self>
707 >: _pin_project::UnsafeUnpin
708 });
709
710 let (impl_generics, _, where_clause) = proj_generics.split_for_impl();
711 let ty_generics = cx.orig.generics.split_for_impl().1;
712
713 quote_spanned! { span =>
714 impl #impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics
715 #where_clause
716 {
717 }
718 }
719 }
720 UnpinImpl::Negative(span) => {
721 let mut proj_generics = cx.proj.generics.clone();
722 let orig_ident = cx.orig.ident;
723 let lifetime = &cx.proj.lifetime;
724
725 proj_generics.make_where_clause().predicates.push(parse_quote! {
728 _pin_project::__private::PinnedFieldsOf<_pin_project::__private::Wrapper<
729 #lifetime, _pin_project::__private::PhantomPinned
730 >>: _pin_project::__private::Unpin
731 });
732
733 let (impl_generics, _, where_clause) = proj_generics.split_for_impl();
734 let ty_generics = cx.orig.generics.split_for_impl().1;
735
736 let unsafety = <Token![unsafe]>::default();
739 quote_spanned! { span =>
740 #[doc(hidden)]
741 impl #impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics
742 #where_clause
743 {
744 }
745
746 #[doc(hidden)]
753 #unsafety impl #impl_generics _pin_project::UnsafeUnpin for #orig_ident #ty_generics
754 #where_clause
755 {
756 }
757 }
758 }
759 UnpinImpl::Default => {
760 let mut impl_where_clause = cx.orig.generics.where_clause.clone().unwrap();
761
762 let fields = cx.pinned_fields.iter().enumerate().map(|(i, ty)| {
765 let field_ident = format_ident!("__field{}", i);
766 quote!(#field_ident: #ty)
767 });
768
769 let lifetime_fields = cx.orig.generics.lifetimes().enumerate().map(
791 |(i, LifetimeParam { lifetime, .. })| {
792 let field_ident = format_ident!("__lifetime{}", i);
793 quote!(#field_ident: &#lifetime ())
794 },
795 );
796
797 let orig_ident = cx.orig.ident;
798 let struct_ident = format_ident!("__{}", orig_ident);
799 let vis = cx.orig.vis;
800 let lifetime = &cx.proj.lifetime;
801 let type_params = cx.orig.generics.type_params().map(|t| &t.ident);
802 let proj_generics = &cx.proj.generics;
803 let (impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl();
804 let (_, ty_generics, ty_where_clause) = cx.orig.generics.split_for_impl();
805
806 impl_where_clause.predicates.push(parse_quote! {
807 _pin_project::__private::PinnedFieldsOf<#struct_ident #proj_ty_generics>:
808 _pin_project::__private::Unpin
809 });
810
811 quote! {
812 #[allow(missing_debug_implementations, unnameable_types)]
823 #vis struct #struct_ident #proj_generics #ty_where_clause {
824 __pin_project_use_generics: _pin_project::__private::AlwaysUnpin<
825 #lifetime, (#(_pin_project::__private::PhantomData<#type_params>),*)
826 >,
827
828 #(#fields,)*
829 #(#lifetime_fields,)*
830 }
831
832 impl #impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics
833 #impl_where_clause
834 {
835 }
836
837 #[doc(hidden)]
844 unsafe impl #impl_generics _pin_project::UnsafeUnpin for #orig_ident #ty_generics
845 #impl_where_clause
846 {
847 }
848 }
849 }
850 }
851}
852
853#[allow(clippy::doc_overindented_list_items)]
854fn make_drop_impl(cx: &Context<'_>) -> TokenStream {
861 let ident = cx.orig.ident;
862 let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
863
864 if let Some(span) = cx.pinned_drop {
865 let unsafety = <Token![unsafe]>::default();
868 quote_spanned! { span =>
869 impl #impl_generics _pin_project::__private::Drop for #ident #ty_generics
870 #where_clause
871 {
872 #[allow(clippy::missing_inline_in_public_items)]
873 fn drop(&mut self) {
874 #unsafety {
875 let __pinned_self = _pin_project::__private::Pin::new_unchecked(self);
878 _pin_project::__private::PinnedDrop::drop(__pinned_self);
882 }
883 }
884 }
885 }
886 } else {
887 let trait_ident = format_ident!("{}MustNotImplDrop", ident);
902
903 quote! {
904 trait #trait_ident {}
912 #[allow(clippy::drop_bounds, drop_bounds)]
913 impl<T: _pin_project::__private::Drop> #trait_ident for T {}
914 impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {}
915
916 #[doc(hidden)]
927 impl #impl_generics _pin_project::__private::PinnedDrop for #ident #ty_generics
928 #where_clause
929 {
930 unsafe fn drop(self: _pin_project::__private::Pin<&mut Self>) {}
931 }
932 }
933 }
934}
935
936fn make_proj_impl(
943 cx: &Context<'_>,
944 proj_body: &TokenStream,
945 proj_ref_body: &TokenStream,
946 proj_own_body: &TokenStream,
947) -> TokenStream {
948 let vis = &cx.proj.vis;
949 let lifetime = &cx.proj.lifetime;
950 let orig_ident = cx.orig.ident;
951 let proj_ident = &cx.proj.mut_ident;
952 let proj_ref_ident = &cx.proj.ref_ident;
953 let proj_own_ident = &cx.proj.own_ident;
954
955 let orig_ty_generics = cx.orig.generics.split_for_impl().1;
956 let proj_ty_generics = cx.proj.generics.split_for_impl().1;
957 let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
958 let allow_dead_code = quote! { #[allow(dead_code)] };
963
964 let mut project = Some(quote! {
965 #allow_dead_code
966 #[inline]
967 #vis fn project<#lifetime>(
968 self: _pin_project::__private::Pin<&#lifetime mut Self>,
969 ) -> #proj_ident #proj_ty_generics {
970 unsafe {
971 #proj_body
972 }
973 }
974 });
975 let mut project_ref = Some(quote! {
976 #allow_dead_code
977 #[inline]
978 #vis fn project_ref<#lifetime>(
979 self: _pin_project::__private::Pin<&#lifetime Self>,
980 ) -> #proj_ref_ident #proj_ty_generics {
981 unsafe {
982 #proj_ref_body
983 }
984 }
985 });
986 let mut project_replace = cx.project_replace.span().map(|span| {
987 let sig = quote_spanned! { span =>
989 #vis fn project_replace(
990 self: _pin_project::__private::Pin<&mut Self>,
991 __replacement: Self,
992 ) -> #proj_own_ident #orig_ty_generics
993 };
994 quote! {
995 #allow_dead_code
996 #[inline]
997 #sig {
998 unsafe {
999 let __self_ptr: *mut Self = self.get_unchecked_mut();
1000
1001 let __guard = _pin_project::__private::UnsafeOverwriteGuard::new(
1004 __self_ptr,
1005 __replacement,
1006 );
1007
1008 #proj_own_body
1009 }
1010 }
1011 }
1012 });
1013
1014 if cx.kind == Enum {
1015 if !cx.project {
1016 project = None;
1017 }
1018 if !cx.project_ref {
1019 project_ref = None;
1020 }
1021 if cx.project_replace.ident().is_none() {
1022 project_replace = None;
1023 }
1024 }
1025
1026 quote! {
1027 impl #impl_generics #orig_ident #ty_generics #where_clause {
1028 #project
1029 #project_ref
1030 #project_replace
1031 }
1032 }
1033}
1034
1035fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> {
1042 for attr in orig.attrs {
1043 if let Meta::List(ref list) = attr.meta {
1044 if list.path.is_ident("repr") {
1045 for repr in list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)? {
1046 if repr.path().is_ident("packed") {
1047 let msg = if fields.is_none() {
1048 "#[repr(packed)] attribute should be applied to a struct or union"
1052 } else if repr.require_name_value().is_ok() {
1053 "#[repr(packed)] attribute should not be name-value pair"
1058 } else {
1059 "#[pin_project] attribute may not be used on #[repr(packed)] types"
1060 };
1061 bail!(repr, msg);
1062 }
1063 }
1064 }
1065 }
1066 }
1067
1068 let fields = match fields {
1069 Some(fields) => fields,
1070 None => return Ok(TokenStream::new()),
1071 };
1072
1073 let mut field_refs = vec![];
1120 match fields {
1121 Fields::Named(FieldsNamed { named, .. }) => {
1122 for Field { ident, .. } in named {
1123 field_refs.push(quote!(&this.#ident));
1124 }
1125 }
1126 Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
1127 for (index, _) in unnamed.iter().enumerate() {
1128 let index = Index::from(index);
1129 field_refs.push(quote!(&this.#index));
1130 }
1131 }
1132 Fields::Unit => {}
1133 }
1134
1135 let (impl_generics, ty_generics, where_clause) = orig.generics.split_for_impl();
1136 let ident = orig.ident;
1137 Ok(quote! {
1138 #[forbid(unaligned_references, safe_packed_borrows)]
1139 fn __assert_not_repr_packed #impl_generics (this: &#ident #ty_generics) #where_clause {
1140 #(let _ = #field_refs;)*
1141 }
1142 })
1143}