1 #![warn(rust_2018_idioms, single_use_lifetimes)]
2 #![allow(dead_code)]
3
4 use pin_project::{pin_project, pinned_drop, UnsafeUnpin};
5 use std::{
6 marker::{PhantomData, PhantomPinned},
7 pin::Pin,
8 };
9
10 #[test]
projection()11 fn projection() {
12 #[pin_project(
13 project = StructProj,
14 project_ref = StructProjRef,
15 project_replace = StructProjOwn,
16 )]
17 struct Struct<T, U> {
18 #[pin]
19 field1: T,
20 field2: U,
21 }
22
23 let mut s = Struct { field1: 1, field2: 2 };
24 let mut s_orig = Pin::new(&mut s);
25 let s = s_orig.as_mut().project();
26
27 let x: Pin<&mut i32> = s.field1;
28 assert_eq!(*x, 1);
29
30 let y: &mut i32 = s.field2;
31 assert_eq!(*y, 2);
32
33 assert_eq!(s_orig.as_ref().field1, 1);
34 assert_eq!(s_orig.as_ref().field2, 2);
35
36 let mut s = Struct { field1: 1, field2: 2 };
37
38 let StructProj { field1, field2 } = Pin::new(&mut s).project();
39 let _: Pin<&mut i32> = field1;
40 let _: &mut i32 = field2;
41
42 let StructProjRef { field1, field2 } = Pin::new(&s).project_ref();
43 let _: Pin<&i32> = field1;
44 let _: &i32 = field2;
45
46 let mut s = Pin::new(&mut s);
47 let StructProjOwn { field1, field2 } =
48 s.as_mut().project_replace(Struct { field1: 3, field2: 4 });
49 let _: PhantomData<i32> = field1;
50 let _: i32 = field2;
51 assert_eq!(field2, 2);
52 assert_eq!(s.field1, 3);
53 assert_eq!(s.field2, 4);
54
55 #[pin_project(project_replace)]
56 struct TupleStruct<T, U>(#[pin] T, U);
57
58 let mut s = TupleStruct(1, 2);
59 let s = Pin::new(&mut s).project();
60
61 let x: Pin<&mut i32> = s.0;
62 assert_eq!(*x, 1);
63
64 let y: &mut i32 = s.1;
65 assert_eq!(*y, 2);
66
67 #[pin_project(project_replace, project = EnumProj)]
68 #[derive(Eq, PartialEq, Debug)]
69 enum Enum<A, B, C, D> {
70 Variant1(#[pin] A, B),
71 Variant2 {
72 #[pin]
73 field1: C,
74 field2: D,
75 },
76 None,
77 }
78
79 let mut e = Enum::Variant1(1, 2);
80 let mut e_orig = Pin::new(&mut e);
81 let e = e_orig.as_mut().project();
82
83 match e {
84 EnumProj::Variant1(x, y) => {
85 let x: Pin<&mut i32> = x;
86 assert_eq!(*x, 1);
87
88 let y: &mut i32 = y;
89 assert_eq!(*y, 2);
90 }
91 EnumProj::Variant2 { field1, field2 } => {
92 let _x: Pin<&mut i32> = field1;
93 let _y: &mut i32 = field2;
94 }
95 EnumProj::None => {}
96 }
97
98 assert_eq!(Pin::into_ref(e_orig).get_ref(), &Enum::Variant1(1, 2));
99
100 let mut e = Enum::Variant2 { field1: 3, field2: 4 };
101 let mut e = Pin::new(&mut e).project();
102
103 match &mut e {
104 EnumProj::Variant1(x, y) => {
105 let _x: &mut Pin<&mut i32> = x;
106 let _y: &mut &mut i32 = y;
107 }
108 EnumProj::Variant2 { field1, field2 } => {
109 let x: &mut Pin<&mut i32> = field1;
110 assert_eq!(**x, 3);
111
112 let y: &mut &mut i32 = field2;
113 assert_eq!(**y, 4);
114 }
115 EnumProj::None => {}
116 }
117
118 if let EnumProj::Variant2 { field1, field2 } = e {
119 let x: Pin<&mut i32> = field1;
120 assert_eq!(*x, 3);
121
122 let y: &mut i32 = field2;
123 assert_eq!(*y, 4);
124 }
125 }
126
127 #[test]
enum_project_set()128 fn enum_project_set() {
129 #[pin_project(project_replace, project = EnumProj)]
130 #[derive(Eq, PartialEq, Debug)]
131 enum Enum {
132 Variant1(#[pin] u8),
133 Variant2(bool),
134 }
135
136 let mut e = Enum::Variant1(25);
137 let mut e_orig = Pin::new(&mut e);
138 let e_proj = e_orig.as_mut().project();
139
140 match e_proj {
141 EnumProj::Variant1(val) => {
142 let new_e = Enum::Variant2(val.as_ref().get_ref() == &25);
143 e_orig.set(new_e);
144 }
145 _ => unreachable!(),
146 }
147
148 assert_eq!(e, Enum::Variant2(true));
149 }
150
151 #[test]
where_clause()152 fn where_clause() {
153 #[pin_project]
154 struct Struct<T>
155 where
156 T: Copy,
157 {
158 field: T,
159 }
160
161 #[pin_project]
162 struct TupleStruct<T>(T)
163 where
164 T: Copy;
165
166 #[pin_project]
167 enum EnumWhere<T>
168 where
169 T: Copy,
170 {
171 Variant(T),
172 }
173 }
174
175 #[test]
where_clause_and_associated_type_field()176 fn where_clause_and_associated_type_field() {
177 #[pin_project(project_replace)]
178 struct Struct1<I>
179 where
180 I: Iterator,
181 {
182 #[pin]
183 field1: I,
184 field2: I::Item,
185 }
186
187 #[pin_project(project_replace)]
188 struct Struct2<I, J>
189 where
190 I: Iterator<Item = J>,
191 {
192 #[pin]
193 field1: I,
194 field2: J,
195 }
196
197 #[pin_project(project_replace)]
198 struct Struct3<T>
199 where
200 T: 'static,
201 {
202 field: T,
203 }
204
205 trait Static: 'static {}
206
207 impl<T> Static for Struct3<T> {}
208
209 #[pin_project(project_replace)]
210 struct TupleStruct<I>(#[pin] I, I::Item)
211 where
212 I: Iterator;
213
214 #[pin_project(project_replace)]
215 enum Enum<I>
216 where
217 I: Iterator,
218 {
219 Variant1(#[pin] I),
220 Variant2(I::Item),
221 }
222 }
223
224 #[test]
derive_copy()225 fn derive_copy() {
226 #[pin_project(project_replace)]
227 #[derive(Clone, Copy)]
228 struct Struct<T> {
229 val: T,
230 }
231
232 fn is_copy<T: Copy>() {}
233
234 is_copy::<Struct<u8>>();
235 }
236
237 #[test]
move_out()238 fn move_out() {
239 struct NotCopy;
240
241 #[pin_project(project_replace)]
242 struct Struct {
243 val: NotCopy,
244 }
245
246 let x = Struct { val: NotCopy };
247 let _val: NotCopy = x.val;
248
249 #[pin_project(project_replace)]
250 enum Enum {
251 Variant(NotCopy),
252 }
253
254 let x = Enum::Variant(NotCopy);
255 #[allow(clippy::infallible_destructuring_match)]
256 let _val: NotCopy = match x {
257 Enum::Variant(val) => val,
258 };
259 }
260
261 #[test]
trait_bounds_on_type_generics()262 fn trait_bounds_on_type_generics() {
263 #[pin_project(project_replace)]
264 pub struct Struct1<'a, T: ?Sized> {
265 field: &'a mut T,
266 }
267
268 #[pin_project(project_replace)]
269 pub struct Struct2<'a, T: ::core::fmt::Debug> {
270 field: &'a mut T,
271 }
272
273 #[pin_project(project_replace)]
274 pub struct Struct3<'a, T: core::fmt::Debug> {
275 field: &'a mut T,
276 }
277
278 #[pin_project(project_replace)]
279 pub struct Struct4<'a, T: core::fmt::Debug + core::fmt::Display> {
280 field: &'a mut T,
281 }
282
283 #[pin_project(project_replace)]
284 pub struct Struct5<'a, T: core::fmt::Debug + ?Sized> {
285 field: &'a mut T,
286 }
287
288 #[pin_project(project_replace)]
289 pub struct Struct6<'a, T: core::fmt::Debug = [u8; 16]> {
290 field: &'a mut T,
291 }
292
293 let _: Struct6<'_> = Struct6 { field: &mut [0u8; 16] };
294
295 #[pin_project(project_replace)]
296 pub struct Struct7<T: 'static> {
297 field: T,
298 }
299
300 trait Static: 'static {}
301
302 impl<T> Static for Struct7<T> {}
303
304 #[pin_project(project_replace)]
305 pub struct Struct8<'a, 'b: 'a> {
306 field1: &'a u8,
307 field2: &'b u8,
308 }
309
310 #[pin_project(project_replace)]
311 pub struct TupleStruct<'a, T: ?Sized>(&'a mut T);
312
313 #[pin_project(project_replace)]
314 enum Enum<'a, T: ?Sized> {
315 Variant(&'a mut T),
316 }
317 }
318
319 #[test]
overlapping_lifetime_names()320 fn overlapping_lifetime_names() {
321 #[pin_project(project_replace)]
322 pub struct Struct1<'pin, T> {
323 #[pin]
324 field: &'pin mut T,
325 }
326
327 #[pin_project(project_replace)]
328 pub struct Struct2<'pin, 'pin_, 'pin__> {
329 #[pin]
330 field: &'pin &'pin_ &'pin__ (),
331 }
332
333 pub trait A<'a> {}
334
335 #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
336 #[pin_project(project_replace)]
337 pub struct HRTB<'pin___, T>
338 where
339 for<'pin> &'pin T: Unpin,
340 T: for<'pin> A<'pin>,
341 for<'pin, 'pin_, 'pin__> &'pin &'pin_ &'pin__ T: Unpin,
342 {
343 #[pin]
344 field: &'pin___ mut T,
345 }
346 }
347
348 #[test]
combine()349 fn combine() {
350 #[pin_project(PinnedDrop, UnsafeUnpin)]
351 pub struct PinnedDropWithUnsafeUnpin<T> {
352 #[pin]
353 field: T,
354 }
355
356 #[pinned_drop]
357 impl<T> PinnedDrop for PinnedDropWithUnsafeUnpin<T> {
358 fn drop(self: Pin<&mut Self>) {}
359 }
360
361 unsafe impl<T: Unpin> UnsafeUnpin for PinnedDropWithUnsafeUnpin<T> {}
362
363 #[pin_project(PinnedDrop, !Unpin)]
364 pub struct PinnedDropWithNotUnpin<T> {
365 #[pin]
366 field: T,
367 }
368
369 #[pinned_drop]
370 impl<T> PinnedDrop for PinnedDropWithNotUnpin<T> {
371 fn drop(self: Pin<&mut Self>) {}
372 }
373
374 #[pin_project(UnsafeUnpin, project_replace)]
375 pub struct UnsafeUnpinWithReplace<T> {
376 #[pin]
377 field: T,
378 }
379
380 unsafe impl<T: Unpin> UnsafeUnpin for UnsafeUnpinWithReplace<T> {}
381
382 #[pin_project(!Unpin, project_replace)]
383 pub struct NotUnpinWithReplace<T> {
384 #[pin]
385 field: T,
386 }
387 }
388
389 #[test]
private_type_in_public_type()390 fn private_type_in_public_type() {
391 #[pin_project(project_replace)]
392 pub struct PublicStruct<T> {
393 #[pin]
394 inner: PrivateStruct<T>,
395 }
396
397 struct PrivateStruct<T>(T);
398 }
399
400 #[test]
lifetime_project()401 fn lifetime_project() {
402 #[pin_project(project_replace)]
403 struct Struct1<T, U> {
404 #[pin]
405 pinned: T,
406 unpinned: U,
407 }
408
409 #[pin_project(project_replace)]
410 struct Struct2<'a, T, U> {
411 #[pin]
412 pinned: &'a mut T,
413 unpinned: U,
414 }
415
416 #[pin_project(project_replace, project = EnumProj, project_ref = EnumProjRef)]
417 enum Enum<T, U> {
418 Variant {
419 #[pin]
420 pinned: T,
421 unpinned: U,
422 },
423 }
424
425 impl<T, U> Struct1<T, U> {
426 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
427 self.project_ref().pinned
428 }
429 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
430 self.project().pinned
431 }
432 }
433
434 impl<'b, T, U> Struct2<'b, T, U> {
435 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a &'b mut T> {
436 self.project_ref().pinned
437 }
438 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut &'b mut T> {
439 self.project().pinned
440 }
441 }
442
443 impl<T, U> Enum<T, U> {
444 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
445 match self.project_ref() {
446 EnumProjRef::Variant { pinned, .. } => pinned,
447 }
448 }
449 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
450 match self.project() {
451 EnumProj::Variant { pinned, .. } => pinned,
452 }
453 }
454 }
455 }
456
457 #[rustversion::since(1.36)] // https://github.com/rust-lang/rust/pull/61207
458 #[test]
lifetime_project_elided()459 fn lifetime_project_elided() {
460 #[pin_project(project_replace)]
461 struct Struct1<T, U> {
462 #[pin]
463 pinned: T,
464 unpinned: U,
465 }
466
467 #[pin_project(project_replace)]
468 struct Struct2<'a, T, U> {
469 #[pin]
470 pinned: &'a mut T,
471 unpinned: U,
472 }
473
474 #[pin_project(project_replace, project = EnumProj, project_ref = EnumProjRef)]
475 enum Enum<T, U> {
476 Variant {
477 #[pin]
478 pinned: T,
479 unpinned: U,
480 },
481 }
482
483 impl<T, U> Struct1<T, U> {
484 fn get_pin_ref(self: Pin<&Self>) -> Pin<&T> {
485 self.project_ref().pinned
486 }
487 fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
488 self.project().pinned
489 }
490 }
491
492 impl<'b, T, U> Struct2<'b, T, U> {
493 fn get_pin_ref(self: Pin<&Self>) -> Pin<&&'b mut T> {
494 self.project_ref().pinned
495 }
496 fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut &'b mut T> {
497 self.project().pinned
498 }
499 }
500
501 impl<T, U> Enum<T, U> {
502 fn get_pin_ref(self: Pin<&Self>) -> Pin<&T> {
503 match self.project_ref() {
504 EnumProjRef::Variant { pinned, .. } => pinned,
505 }
506 }
507 fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
508 match self.project() {
509 EnumProj::Variant { pinned, .. } => pinned,
510 }
511 }
512 }
513 }
514
515 mod visibility {
516 use pin_project::pin_project;
517
518 #[pin_project(project_replace)]
519 pub(crate) struct A {
520 pub b: u8,
521 }
522 }
523
524 #[test]
visibility()525 fn visibility() {
526 let mut x = visibility::A { b: 0 };
527 let x = Pin::new(&mut x);
528 let y = x.as_ref().project_ref();
529 let _: &u8 = y.b;
530 let y = x.project();
531 let _: &mut u8 = y.b;
532 }
533
534 #[test]
trivial_bounds()535 fn trivial_bounds() {
536 #[pin_project(project_replace)]
537 pub struct NoGenerics {
538 #[pin]
539 field: PhantomPinned,
540 }
541 }
542
543 #[test]
dst()544 fn dst() {
545 #[pin_project]
546 struct Struct1<T: ?Sized> {
547 x: T,
548 }
549
550 let mut x = Struct1 { x: 0_u8 };
551 let x: Pin<&mut Struct1<dyn core::fmt::Debug>> = Pin::new(&mut x as _);
552 let _y: &mut (dyn core::fmt::Debug) = x.project().x;
553
554 #[pin_project]
555 struct Struct2<T: ?Sized> {
556 #[pin]
557 x: T,
558 }
559
560 let mut x = Struct2 { x: 0_u8 };
561 let x: Pin<&mut Struct2<dyn core::fmt::Debug + Unpin>> = Pin::new(&mut x as _);
562 let _y: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().x;
563
564 #[pin_project(UnsafeUnpin)]
565 struct Struct5<T: ?Sized> {
566 x: T,
567 }
568
569 #[pin_project(UnsafeUnpin)]
570 struct Struct6<T: ?Sized> {
571 #[pin]
572 x: T,
573 }
574
575 #[pin_project(PinnedDrop)]
576 struct Struct7<T: ?Sized> {
577 x: T,
578 }
579
580 #[pinned_drop]
581 impl<T: ?Sized> PinnedDrop for Struct7<T> {
582 fn drop(self: Pin<&mut Self>) {}
583 }
584
585 #[pin_project(PinnedDrop)]
586 struct Struct8<T: ?Sized> {
587 #[pin]
588 x: T,
589 }
590
591 #[pinned_drop]
592 impl<T: ?Sized> PinnedDrop for Struct8<T> {
593 fn drop(self: Pin<&mut Self>) {}
594 }
595
596 #[pin_project(!Unpin)]
597 struct Struct9<T: ?Sized> {
598 x: T,
599 }
600
601 #[pin_project(!Unpin)]
602 struct Struct10<T: ?Sized> {
603 #[pin]
604 x: T,
605 }
606
607 #[pin_project]
608 struct TupleStruct1<T: ?Sized>(T);
609
610 #[pin_project]
611 struct TupleStruct2<T: ?Sized>(#[pin] T);
612
613 #[pin_project(UnsafeUnpin)]
614 struct TupleStruct5<T: ?Sized>(T);
615
616 #[pin_project(UnsafeUnpin)]
617 struct TupleStruct6<T: ?Sized>(#[pin] T);
618
619 #[pin_project(PinnedDrop)]
620 struct TupleStruct7<T: ?Sized>(T);
621
622 #[pinned_drop]
623 impl<T: ?Sized> PinnedDrop for TupleStruct7<T> {
624 fn drop(self: Pin<&mut Self>) {}
625 }
626
627 #[pin_project(PinnedDrop)]
628 struct TupleStruct8<T: ?Sized>(#[pin] T);
629
630 #[pinned_drop]
631 impl<T: ?Sized> PinnedDrop for TupleStruct8<T> {
632 fn drop(self: Pin<&mut Self>) {}
633 }
634
635 #[pin_project(!Unpin)]
636 struct TupleStruct9<T: ?Sized>(T);
637
638 #[pin_project(!Unpin)]
639 struct TupleStruct10<T: ?Sized>(#[pin] T);
640 }
641
642 #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
643 #[test]
unsized_in_where_clause()644 fn unsized_in_where_clause() {
645 #[pin_project]
646 struct Struct3<T>
647 where
648 T: ?Sized,
649 {
650 x: T,
651 }
652
653 #[pin_project]
654 struct Struct4<T>
655 where
656 T: ?Sized,
657 {
658 #[pin]
659 x: T,
660 }
661
662 #[pin_project]
663 struct TupleStruct3<T>(T)
664 where
665 T: ?Sized;
666
667 #[pin_project]
668 struct TupleStruct4<T>(#[pin] T)
669 where
670 T: ?Sized;
671 }
672
673 #[test]
dyn_type()674 fn dyn_type() {
675 #[pin_project]
676 struct Struct1 {
677 f: dyn core::fmt::Debug,
678 }
679
680 #[pin_project]
681 struct Struct2 {
682 #[pin]
683 f: dyn core::fmt::Debug,
684 }
685
686 #[pin_project]
687 struct Struct3 {
688 f: dyn core::fmt::Debug + Send,
689 }
690
691 #[pin_project]
692 struct Struct4 {
693 #[pin]
694 f: dyn core::fmt::Debug + Send,
695 }
696
697 #[pin_project]
698 struct TupleStruct1(dyn core::fmt::Debug);
699
700 #[pin_project]
701 struct TupleStruct2(#[pin] dyn core::fmt::Debug);
702
703 #[pin_project]
704 struct TupleStruct3(dyn core::fmt::Debug + Send);
705
706 #[pin_project]
707 struct TupleStruct4(#[pin] dyn core::fmt::Debug + Send);
708 }
709
710 #[test]
parse_self()711 fn parse_self() {
712 macro_rules! mac {
713 ($($tt:tt)*) => {
714 $($tt)*
715 };
716 }
717
718 pub trait Trait {
719 type Assoc;
720 }
721
722 #[pin_project(project_replace)]
723 pub struct Generics<T: Trait<Assoc = Self>>
724 where
725 Self: Trait<Assoc = Self>,
726 <Self as Trait>::Assoc: Sized,
727 mac!(Self): Trait<Assoc = mac!(Self)>,
728 {
729 _f: T,
730 }
731
732 impl<T: Trait<Assoc = Self>> Trait for Generics<T> {
733 type Assoc = Self;
734 }
735
736 #[pin_project(project_replace)]
737 pub struct Struct {
738 _f1: Box<Self>,
739 _f2: Box<<Self as Trait>::Assoc>,
740 _f3: Box<mac!(Self)>,
741 _f4: [(); Self::ASSOC],
742 _f5: [(); Self::assoc()],
743 _f6: [(); mac!(Self::assoc())],
744 }
745
746 impl Struct {
747 const ASSOC: usize = 1;
748 const fn assoc() -> usize {
749 0
750 }
751 }
752
753 impl Trait for Struct {
754 type Assoc = Self;
755 }
756
757 #[pin_project(project_replace)]
758 struct Tuple(
759 Box<Self>,
760 Box<<Self as Trait>::Assoc>,
761 Box<mac!(Self)>,
762 [(); Self::ASSOC],
763 [(); Self::assoc()],
764 [(); mac!(Self::assoc())],
765 );
766
767 impl Tuple {
768 const ASSOC: usize = 1;
769 const fn assoc() -> usize {
770 0
771 }
772 }
773
774 impl Trait for Tuple {
775 type Assoc = Self;
776 }
777
778 #[pin_project(project_replace)]
779 enum Enum {
780 Struct {
781 _f1: Box<Self>,
782 _f2: Box<<Self as Trait>::Assoc>,
783 _f3: Box<mac!(Self)>,
784 _f4: [(); Self::ASSOC],
785 _f5: [(); Self::assoc()],
786 _f6: [(); mac!(Self::assoc())],
787 },
788 Tuple(
789 Box<Self>,
790 Box<<Self as Trait>::Assoc>,
791 Box<mac!(Self)>,
792 [(); Self::ASSOC],
793 [(); Self::assoc()],
794 [(); mac!(Self::assoc())],
795 ),
796 }
797
798 impl Enum {
799 const ASSOC: usize = 1;
800 const fn assoc() -> usize {
801 0
802 }
803 }
804
805 impl Trait for Enum {
806 type Assoc = Self;
807 }
808 }
809
810 #[test]
811 fn no_infer_outlives() {
812 trait Bar<X> {
813 type Y;
814 }
815
816 struct Example<A>(A);
817
818 impl<X, T> Bar<X> for Example<T> {
819 type Y = Option<T>;
820 }
821
822 #[pin_project(project_replace)]
823 struct Foo<A, B> {
824 _x: <Example<A> as Bar<B>>::Y,
825 }
826 }
827
828 // https://github.com/rust-lang/rust/issues/47949
829 // https://github.com/taiki-e/pin-project/pull/194#discussion_r419098111
830 #[allow(clippy::many_single_char_names)]
831 #[test]
832 fn project_replace_panic() {
833 use std::panic;
834
835 #[pin_project(project_replace)]
836 struct S<T, U> {
837 #[pin]
838 pinned: T,
839 unpinned: U,
840 }
841
842 struct D<'a>(&'a mut bool, bool);
843 impl Drop for D<'_> {
844 fn drop(&mut self) {
845 *self.0 = true;
846 if self.1 {
847 panic!()
848 }
849 }
850 }
851
852 let (mut a, mut b, mut c, mut d) = (false, false, false, false);
853 let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
854 let mut x = S { pinned: D(&mut a, true), unpinned: D(&mut b, false) };
855 let _y = Pin::new(&mut x)
856 .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) });
857 // Previous `x.pinned` was dropped and panicked when `project_replace` is
858 // called, so this is unreachable.
859 unreachable!();
860 }));
861 assert!(res.is_err());
862 assert!(a);
863 assert!(b);
864 assert!(c);
865 assert!(d);
866
867 let (mut a, mut b, mut c, mut d) = (false, false, false, false);
868 let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
869 let mut x = S { pinned: D(&mut a, false), unpinned: D(&mut b, true) };
870 {
871 let _y = Pin::new(&mut x)
872 .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) });
873 // `_y` (previous `x.unpinned`) live to the end of this scope, so
874 // this is not unreachable.
875 // unreachable!();
876 }
877 unreachable!();
878 }));
879 assert!(res.is_err());
880 assert!(a);
881 assert!(b);
882 assert!(c);
883 assert!(d);
884 }
885