1#![warn(rust_2018_idioms, single_use_lifetimes)]
2#![allow(dead_code)]
3
4#[macro_use]
5mod auxiliary;
6
7use core::{
8 marker::{PhantomData, PhantomPinned},
9 pin::Pin,
10};
11
12use pin_project_lite::pin_project;
13
14#[test]
15fn 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]
106fn 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]
133fn 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]
156fn 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]
206fn 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]
220fn 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]
248fn 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]
314fn 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]
327fn 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
410mod 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]
421fn 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]
431fn 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]
443fn 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]
493fn 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]
522fn 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]
542fn 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]
589fn 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(!Unpin)]
620 #[project = Enum2Proj]
621 #[project_ref = Enum2ProjRef]
622 /// dox2
623 #[derive(Debug)]
624 /// dox3
625 enum Enum2 {
626 /// dox4
627 V1 {
628 // TODO
629 // /// dox5
630 f: ()
631 },
632 /// dox6
633 V2,
634 }
635 }
636}
637
638#[test]
639fn pinned_drop() {
640 pin_project! {
641 pub struct Struct1<'a> {
642 was_dropped: &'a mut bool,
643 #[pin]
644 field: u8,
645 }
646 impl PinnedDrop for Struct1<'_> {
647 fn drop(this: Pin<&mut Self>) {
648 **this.project().was_dropped = true;
649 }
650 }
651 }
652
653 let mut was_dropped = false;
654 drop(Struct1 { was_dropped: &mut was_dropped, field: 42 });
655 assert!(was_dropped);
656
657 pin_project! {
658 pub struct Struct2<'a> {
659 was_dropped: &'a mut bool,
660 #[pin]
661 field: u8,
662 }
663 impl PinnedDrop for Struct2<'_> {
664 fn drop(mut this: Pin<&mut Self>) {
665 **this.as_mut().project().was_dropped = true;
666 }
667 }
668 }
669
670 trait Service<Request> {
671 type Error;
672 }
673
674 pin_project! {
675 struct Struct3<'a, T, Request>
676 where
677 T: Service<Request>,
678 T::Error: std::error::Error,
679 {
680 was_dropped: &'a mut bool,
681 #[pin]
682 field: T,
683 req: Request,
684 }
685
686 /// dox1
687 impl<T, Request> PinnedDrop for Struct3<'_, T, Request>
688 where
689 T: Service<Request>,
690 T::Error: std::error::Error,
691 {
692 /// dox2
693 fn drop(mut this: Pin<&mut Self>) {
694 **this.as_mut().project().was_dropped = true;
695 }
696 }
697 }
698}
699