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