1 #![warn(rust_2018_idioms, single_use_lifetimes)]
2 #![allow(dead_code)]
3 
4 #[macro_use]
5 mod auxiliary;
6 
7 use core::{
8     marker::{PhantomData, PhantomPinned},
9     pin::Pin,
10 };
11 
12 use pin_project_lite::pin_project;
13 
14 #[test]
projection()15 fn projection() {
16     pin_project! {
17         #[project = StructProj]
18         #[project_ref = StructProjRef]
19         #[project_replace = StructProjReplace]
20         #[derive(Default)]
21         struct Struct<T, U> {
22             #[pin]
23             f1: T,
24             f2: U,
25         }
26     }
27 
28     let mut s = Struct { f1: 1, f2: 2 };
29     let mut s_orig = Pin::new(&mut s);
30     let s = s_orig.as_mut().project();
31 
32     let _: Pin<&mut i32> = s.f1;
33     assert_eq!(*s.f1, 1);
34     let _: &mut i32 = s.f2;
35     assert_eq!(*s.f2, 2);
36 
37     assert_eq!(s_orig.as_ref().f1, 1);
38     assert_eq!(s_orig.as_ref().f2, 2);
39 
40     let mut s = Struct { f1: 1, f2: 2 };
41     let mut s = Pin::new(&mut s);
42     {
43         let StructProj { f1, f2 } = s.as_mut().project();
44         let _: Pin<&mut i32> = f1;
45         let _: &mut i32 = f2;
46     }
47     {
48         let StructProjRef { f1, f2 } = s.as_ref().project_ref();
49         let _: Pin<&i32> = f1;
50         let _: &i32 = f2;
51     }
52 
53     {
54         let StructProjReplace { f1: PhantomData, f2 } =
55             s.as_mut().project_replace(Struct::default());
56         assert_eq!(f2, 2);
57         let StructProj { f1, f2 } = s.project();
58         assert_eq!(*f1, 0);
59         assert_eq!(*f2, 0);
60     }
61 
62     pin_project! {
63         #[project = EnumProj]
64         #[project_ref = EnumProjRef]
65         #[project_replace = EnumProjReplace]
66         #[derive(Eq, PartialEq, Debug)]
67         enum Enum<C, D> {
68             Struct {
69                 #[pin]
70                 f1: C,
71                 f2: D,
72             },
73             Unit,
74         }
75     }
76 
77     let mut e = Enum::Struct { f1: 1, f2: 2 };
78     let mut e = Pin::new(&mut e);
79 
80     match e.as_mut().project() {
81         EnumProj::Struct { f1, f2 } => {
82             let _: Pin<&mut i32> = f1;
83             assert_eq!(*f1, 1);
84             let _: &mut i32 = f2;
85             assert_eq!(*f2, 2);
86         }
87         EnumProj::Unit => unreachable!(),
88     }
89 
90     assert_eq!(&*e, &Enum::Struct { f1: 1, f2: 2 });
91 
92     if let EnumProj::Struct { f1, f2 } = e.as_mut().project() {
93         let _: Pin<&mut i32> = f1;
94         assert_eq!(*f1, 1);
95         let _: &mut i32 = f2;
96         assert_eq!(*f2, 2);
97     }
98 
99     if let EnumProjReplace::Struct { f1: PhantomData, f2 } = e.as_mut().project_replace(Enum::Unit)
100     {
101         assert_eq!(f2, 2);
102     }
103 }
104 
105 #[test]
enum_project_set()106 fn enum_project_set() {
107     pin_project! {
108         #[project = EnumProj]
109         #[project_ref = EnumProjRef]
110         #[derive(Eq, PartialEq, Debug)]
111         enum Enum {
112             V1 { #[pin] f: u8 },
113             V2 { f: bool },
114         }
115     }
116 
117     let mut e = Enum::V1 { f: 25 };
118     let mut e_orig = Pin::new(&mut e);
119     let e_proj = e_orig.as_mut().project();
120 
121     match e_proj {
122         EnumProj::V1 { f } => {
123             let new_e = Enum::V2 { f: f.as_ref().get_ref() == &25 };
124             e_orig.set(new_e);
125         }
126         EnumProj::V2 { .. } => unreachable!(),
127     }
128 
129     assert_eq!(e, Enum::V2 { f: true });
130 }
131 
132 #[test]
where_clause()133 fn where_clause() {
134     pin_project! {
135         struct Struct<T>
136         where
137             T: Copy,
138         {
139             f: T,
140         }
141     }
142 
143     pin_project! {
144         #[project = EnumProj]
145         #[project_ref = EnumProjRef]
146         enum Enum<T>
147         where
148             T: Copy,
149         {
150             V { f: T },
151         }
152     }
153 }
154 
155 #[test]
where_clause_and_associated_type_field()156 fn where_clause_and_associated_type_field() {
157     pin_project! {
158         struct Struct1<I>
159         where
160             I: Iterator,
161         {
162             #[pin]
163             f1: I,
164             f2: I::Item,
165         }
166     }
167 
168     pin_project! {
169         struct Struct2<I, J>
170         where
171             I: Iterator<Item = J>,
172         {
173             #[pin]
174             f1: I,
175             f2: J,
176         }
177     }
178 
179     pin_project! {
180         pub struct Struct3<T>
181         where
182             T: 'static,
183         {
184             f: T,
185         }
186     }
187 
188     trait Static: 'static {}
189 
190     impl<T> Static for Struct3<T> {}
191 
192     pin_project! {
193         #[project = EnumProj]
194         #[project_ref = EnumProjRef]
195         enum Enum<I>
196         where
197             I: Iterator,
198         {
199             V1 { #[pin] f: I },
200             V2 { f: I::Item },
201         }
202     }
203 }
204 
205 #[test]
derive_copy()206 fn derive_copy() {
207     pin_project! {
208         #[derive(Clone, Copy)]
209         struct Struct<T> {
210             f: T,
211         }
212     }
213 
214     fn is_copy<T: Copy>() {}
215 
216     is_copy::<Struct<u8>>();
217 }
218 
219 #[test]
move_out()220 fn move_out() {
221     struct NotCopy;
222 
223     pin_project! {
224         struct Struct {
225             f: NotCopy,
226         }
227     }
228 
229     let x = Struct { f: NotCopy };
230     let _val: NotCopy = x.f;
231 
232     pin_project! {
233         #[project = EnumProj]
234         #[project_ref = EnumProjRef]
235         enum Enum {
236             V { f: NotCopy },
237         }
238     }
239 
240     let x = Enum::V { f: NotCopy };
241     #[allow(clippy::infallible_destructuring_match)]
242     let _val: NotCopy = match x {
243         Enum::V { f } => f,
244     };
245 }
246 
247 #[test]
trait_bounds_on_type_generics()248 fn trait_bounds_on_type_generics() {
249     pin_project! {
250         pub struct Struct1<'a, T: ?Sized> {
251             f: &'a mut T,
252         }
253     }
254 
255     pin_project! {
256         pub struct Struct2<'a, T: ::core::fmt::Debug> {
257             f: &'a mut T,
258         }
259     }
260 
261     pin_project! {
262         pub struct Struct3<'a, T: core::fmt::Debug> {
263             f: &'a mut T,
264         }
265     }
266 
267     // pin_project! {
268     //     pub struct Struct4<'a, T: core::fmt::Debug + core::fmt::Display> {
269     //         f: &'a mut T,
270     //     }
271     // }
272 
273     // pin_project! {
274     //     pub struct Struct5<'a, T: core::fmt::Debug + ?Sized> {
275     //         f: &'a mut T,
276     //     }
277     // }
278 
279     pin_project! {
280         pub struct Struct6<'a, T: core::fmt::Debug = [u8; 16]> {
281             f: &'a mut T,
282         }
283     }
284 
285     let _: Struct6<'_> = Struct6 { f: &mut [0_u8; 16] };
286 
287     pin_project! {
288         pub struct Struct7<T: 'static> {
289             f: T,
290         }
291     }
292 
293     trait Static: 'static {}
294 
295     impl<T> Static for Struct7<T> {}
296 
297     pin_project! {
298         pub struct Struct8<'a, 'b: 'a> {
299             f1: &'a u8,
300             f2: &'b u8,
301         }
302     }
303 
304     pin_project! {
305         #[project = EnumProj]
306         #[project_ref = EnumProjRef]
307         enum Enum<'a, T: ?Sized> {
308             V { f: &'a mut T },
309         }
310     }
311 }
312 
313 #[test]
private_type_in_public_type()314 fn private_type_in_public_type() {
315     pin_project! {
316         pub struct PublicStruct<T> {
317             #[pin]
318             inner: PrivateStruct<T>,
319         }
320     }
321 
322     struct PrivateStruct<T>(T);
323 }
324 
325 #[allow(clippy::needless_lifetimes)]
326 #[test]
lifetime_project()327 fn lifetime_project() {
328     pin_project! {
329         struct Struct1<T, U> {
330             #[pin]
331             pinned: T,
332             unpinned: U,
333         }
334     }
335 
336     pin_project! {
337         struct Struct2<'a, T, U> {
338             #[pin]
339             pinned: &'a T,
340             unpinned: U,
341         }
342     }
343 
344     pin_project! {
345         #[project = EnumProj]
346         #[project_ref = EnumProjRef]
347         enum Enum<T, U> {
348             V {
349                 #[pin]
350                 pinned: T,
351                 unpinned: U,
352             },
353         }
354     }
355 
356     impl<T, U> Struct1<T, U> {
357         fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
358             self.project_ref().pinned
359         }
360         fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
361             self.project().pinned
362         }
363         fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&T> {
364             self.project_ref().pinned
365         }
366         fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> {
367             self.project().pinned
368         }
369     }
370 
371     impl<'b, T, U> Struct2<'b, T, U> {
372         fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a &'b T> {
373             self.project_ref().pinned
374         }
375         fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut &'b T> {
376             self.project().pinned
377         }
378         fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&&'b T> {
379             self.project_ref().pinned
380         }
381         fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut &'b T> {
382             self.project().pinned
383         }
384     }
385 
386     impl<T, U> Enum<T, U> {
387         fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
388             match self.project_ref() {
389                 EnumProjRef::V { pinned, .. } => pinned,
390             }
391         }
392         fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
393             match self.project() {
394                 EnumProj::V { pinned, .. } => pinned,
395             }
396         }
397         fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&T> {
398             match self.project_ref() {
399                 EnumProjRef::V { pinned, .. } => pinned,
400             }
401         }
402         fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> {
403             match self.project() {
404                 EnumProj::V { pinned, .. } => pinned,
405             }
406         }
407     }
408 }
409 
410 mod visibility {
411     use pin_project_lite::pin_project;
412 
413     pin_project! {
414         pub(crate) struct S {
415             pub f: u8,
416         }
417     }
418 }
419 
420 #[test]
visibility()421 fn visibility() {
422     let mut x = visibility::S { f: 0 };
423     let x = Pin::new(&mut x);
424     let y = x.as_ref().project_ref();
425     let _: &u8 = y.f;
426     let y = x.project();
427     let _: &mut u8 = y.f;
428 }
429 
430 #[test]
trivial_bounds()431 fn trivial_bounds() {
432     pin_project! {
433         pub struct NoGenerics {
434             #[pin]
435             f: PhantomPinned,
436         }
437     }
438 
439     assert_not_unpin!(NoGenerics);
440 }
441 
442 #[test]
dst()443 fn dst() {
444     pin_project! {
445         pub struct Struct1<T: ?Sized> {
446             f: T,
447         }
448     }
449 
450     let mut x = Struct1 { f: 0_u8 };
451     let x: Pin<&mut Struct1<dyn core::fmt::Debug>> = Pin::new(&mut x as _);
452     let _: &mut (dyn core::fmt::Debug) = x.project().f;
453 
454     pin_project! {
455         pub struct Struct2<T: ?Sized> {
456             #[pin]
457             f: T,
458         }
459     }
460 
461     let mut x = Struct2 { f: 0_u8 };
462     let x: Pin<&mut Struct2<dyn core::fmt::Debug + Unpin>> = Pin::new(&mut x as _);
463     let _: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().f;
464 
465     pin_project! {
466         struct Struct3<T>
467         where
468             T: ?Sized,
469         {
470             f: T,
471         }
472     }
473 
474     pin_project! {
475         struct Struct4<T>
476         where
477             T: ?Sized,
478         {
479             #[pin]
480             f: T,
481         }
482     }
483 
484     pin_project! {
485         struct Struct11<'a, T: ?Sized, U: ?Sized> {
486             f1: &'a mut T,
487             f2: U,
488         }
489     }
490 }
491 
492 #[test]
dyn_type()493 fn dyn_type() {
494     pin_project! {
495         struct Struct1 {
496             f: dyn core::fmt::Debug,
497         }
498     }
499 
500     pin_project! {
501         struct Struct2 {
502             #[pin]
503             f: dyn core::fmt::Debug,
504         }
505     }
506 
507     pin_project! {
508         struct Struct3 {
509             f: dyn core::fmt::Debug + Send,
510         }
511     }
512 
513     pin_project! {
514         struct Struct4 {
515             #[pin]
516             f: dyn core::fmt::Debug + Send,
517         }
518     }
519 }
520 
521 #[test]
no_infer_outlives()522 fn no_infer_outlives() {
523     trait Trait<X> {
524         type Y;
525     }
526 
527     struct Struct1<A>(A);
528 
529     impl<X, T> Trait<X> for Struct1<T> {
530         type Y = Option<T>;
531     }
532 
533     pin_project! {
534         struct Struct2<A, B> {
535             _f: <Struct1<A> as Trait<B>>::Y,
536         }
537     }
538 }
539 
540 // https://github.com/taiki-e/pin-project-lite/issues/31
541 #[test]
trailing_comma()542 fn trailing_comma() {
543     pub trait T {}
544 
545     pin_project! {
546         pub struct S1<
547             A: T,
548             B: T,
549         > {
550             f: (A, B),
551         }
552     }
553 
554     pin_project! {
555         pub struct S2<
556             A,
557             B,
558         >
559         where
560             A: T,
561             B: T,
562         {
563             f: (A, B),
564         }
565     }
566 
567     pin_project! {
568         #[allow(explicit_outlives_requirements)]
569         pub struct S3<
570             'a,
571             A: 'a,
572             B: 'a,
573         > {
574             f: &'a (A, B),
575         }
576     }
577 
578     // pin_project! {
579     //     pub struct S4<
580     //         'a,
581     //         'b: 'a, // <-----
582     //     > {
583     //         f: &'a &'b (),
584     //     }
585     // }
586 }
587 
588 #[test]
attrs()589 fn attrs() {
590     pin_project! {
591         /// dox1
592         #[derive(Clone)]
593         #[project = StructProj]
594         #[project_ref = StructProjRef]
595         /// dox2
596         #[derive(Debug)]
597         /// dox3
598         struct Struct {
599             // TODO
600             // /// dox4
601             f: ()
602         }
603     }
604 
605     pin_project! {
606         #[project = Enum1Proj]
607         #[project_ref = Enum1ProjRef]
608         enum Enum1 {
609             #[cfg(not(any()))]
610             V {
611                 f: ()
612             },
613         }
614     }
615 
616     pin_project! {
617         /// dox1
618         #[derive(Clone)]
619         #[project = Enum2Proj]
620         #[project_ref = Enum2ProjRef]
621         /// dox2
622         #[derive(Debug)]
623         /// dox3
624         enum Enum2 {
625             /// dox4
626             V1 {
627                 // TODO
628                 // /// dox5
629                 f: ()
630             },
631             /// dox6
632             V2,
633         }
634     }
635 }
636 
637 #[test]
pinned_drop()638 fn pinned_drop() {
639     pin_project! {
640         pub struct Struct1<'a> {
641             was_dropped: &'a mut bool,
642             #[pin]
643             field: u8,
644         }
645         impl PinnedDrop for Struct1<'_> {
646             fn drop(this: Pin<&mut Self>) {
647                 **this.project().was_dropped = true;
648             }
649         }
650     }
651 
652     let mut was_dropped = false;
653     drop(Struct1 { was_dropped: &mut was_dropped, field: 42 });
654     assert!(was_dropped);
655 
656     pin_project! {
657         pub struct Struct2<'a> {
658             was_dropped: &'a mut bool,
659             #[pin]
660             field: u8,
661         }
662         impl PinnedDrop for Struct2<'_> {
663             fn drop(mut this: Pin<&mut Self>) {
664                 **this.as_mut().project().was_dropped = true;
665             }
666         }
667     }
668 
669     trait Service<Request> {
670         type Error;
671     }
672 
673     pin_project! {
674         struct Struct3<'a, T, Request>
675         where
676             T: Service<Request>,
677             T::Error: std::error::Error,
678         {
679             was_dropped: &'a mut bool,
680             #[pin]
681             field: T,
682             req: Request,
683         }
684 
685         impl<T, Request> PinnedDrop for Struct3<'_, T, Request>
686         where
687             T: Service<Request>,
688             T::Error: std::error::Error,
689         {
690             fn drop(mut this: Pin<&mut Self>) {
691                 **this.as_mut().project().was_dropped = true;
692             }
693         }
694     }
695 }
696