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