blob: 72bcd15260066eeabb9c0b7b9b3eea27e147f3ff [file] [log] [blame]
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -07001#![warn(rust_2018_idioms, single_use_lifetimes)]
2#![allow(dead_code)]
3
4use core::{
5 marker::{PhantomData, PhantomPinned},
6 pin::Pin,
7};
8use pin_project::{pin_project, pinned_drop, UnsafeUnpin};
9
10#[test]
11fn projection() {
Haibo Huang2960bb32020-05-18 15:51:06 -070012 #[pin_project(
13 Replace,
14 project = StructProj,
15 project_ref = StructProjRef,
16 project_replace = StructProjOwn,
17 )]
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -070018 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
Haibo Huang2960bb32020-05-18 15:51:06 -070039 let StructProj { field1, field2 } = Pin::new(&mut s).project();
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -070040 let _: Pin<&mut i32> = field1;
41 let _: &mut i32 = field2;
42
Haibo Huang2960bb32020-05-18 15:51:06 -070043 let StructProjRef { field1, field2 } = Pin::new(&s).project_ref();
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -070044 let _: Pin<&i32> = field1;
45 let _: &i32 = field2;
46
47 let mut s = Pin::new(&mut s);
Haibo Huang2960bb32020-05-18 15:51:06 -070048 let StructProjOwn { field1, field2 } =
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -070049 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(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
Haibo Huang2960bb32020-05-18 15:51:06 -070068 #[pin_project(Replace, project = EnumProj)]
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -070069 #[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 {
Haibo Huang2960bb32020-05-18 15:51:06 -070085 EnumProj::Variant1(x, y) => {
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -070086 let x: Pin<&mut i32> = x;
87 assert_eq!(*x, 1);
88
89 let y: &mut i32 = y;
90 assert_eq!(*y, 2);
91 }
Haibo Huang2960bb32020-05-18 15:51:06 -070092 EnumProj::Variant2 { field1, field2 } => {
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -070093 let _x: Pin<&mut i32> = field1;
94 let _y: &mut i32 = field2;
95 }
Haibo Huang2960bb32020-05-18 15:51:06 -070096 EnumProj::None => {}
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -070097 }
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 {
Haibo Huang2960bb32020-05-18 15:51:06 -0700105 EnumProj::Variant1(x, y) => {
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700106 let _x: &mut Pin<&mut i32> = x;
107 let _y: &mut &mut i32 = y;
108 }
Haibo Huang2960bb32020-05-18 15:51:06 -0700109 EnumProj::Variant2 { field1, field2 } => {
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700110 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 }
Haibo Huang2960bb32020-05-18 15:51:06 -0700116 EnumProj::None => {}
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700117 }
118
Haibo Huang2960bb32020-05-18 15:51:06 -0700119 if let EnumProj::Variant2 { field1, field2 } = e {
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700120 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]
129fn enum_project_set() {
Haibo Huang2960bb32020-05-18 15:51:06 -0700130 #[pin_project(Replace, project = EnumProj)]
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700131 #[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 {
Haibo Huang2960bb32020-05-18 15:51:06 -0700142 EnumProj::Variant1(val) => {
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700143 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]
153fn 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]
177fn where_clause_and_associated_type_field() {
178 #[pin_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(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(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(Replace)]
211 struct TupleStruct<I>(#[pin] I, I::Item)
212 where
213 I: Iterator;
214
215 #[pin_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]
226fn derive_copy() {
227 #[pin_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]
239fn move_out() {
240 struct NotCopy;
241
242 #[pin_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(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]
263fn trait_bounds_on_type_generics() {
264 #[pin_project(Replace)]
265 pub struct Struct1<'a, T: ?Sized> {
266 field: &'a mut T,
267 }
268
269 #[pin_project(Replace)]
270 pub struct Struct2<'a, T: ::core::fmt::Debug> {
271 field: &'a mut T,
272 }
273
274 #[pin_project(Replace)]
275 pub struct Struct3<'a, T: core::fmt::Debug> {
276 field: &'a mut T,
277 }
278
279 #[pin_project(Replace)]
280 pub struct Struct4<'a, T: core::fmt::Debug + core::fmt::Display> {
281 field: &'a mut T,
282 }
283
284 #[pin_project(Replace)]
285 pub struct Struct5<'a, T: core::fmt::Debug + ?Sized> {
286 field: &'a mut T,
287 }
288
289 #[pin_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(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(Replace)]
306 pub struct Struct8<'a, 'b: 'a> {
307 field1: &'a u8,
308 field2: &'b u8,
309 }
310
311 #[pin_project(Replace)]
312 pub struct TupleStruct<'a, T: ?Sized>(&'a mut T);
313
314 #[pin_project(Replace)]
315 enum Enum<'a, T: ?Sized> {
316 Variant(&'a mut T),
317 }
318}
319
320#[test]
321fn overlapping_lifetime_names() {
322 #[pin_project(Replace)]
323 pub struct Struct1<'pin, T> {
324 #[pin]
325 field: &'pin mut T,
326 }
327
328 #[pin_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(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]
350fn combine() {
351 #[pin_project(PinnedDrop, UnsafeUnpin)]
352 pub struct Struct1<T> {
353 #[pin]
354 field: T,
355 }
356
357 #[pinned_drop]
358 impl<T> PinnedDrop for Struct1<T> {
359 fn drop(self: Pin<&mut Self>) {}
360 }
361
362 unsafe impl<T: Unpin> UnsafeUnpin for Struct1<T> {}
363
364 #[pin_project(UnsafeUnpin, Replace)]
365 pub struct Struct2<T> {
366 #[pin]
367 field: T,
368 }
369
370 unsafe impl<T: Unpin> UnsafeUnpin for Struct2<T> {}
371
372 #[pin_project(PinnedDrop, !Unpin)]
373 pub struct Struct3<T> {
374 #[pin]
375 field: T,
376 }
377
378 #[pinned_drop]
379 impl<T> PinnedDrop for Struct3<T> {
380 fn drop(self: Pin<&mut Self>) {}
381 }
382
383 #[pin_project(!Unpin, Replace)]
384 pub struct Struct4<T> {
385 #[pin]
386 field: T,
387 }
388}
389
390#[test]
391fn private_type_in_public_type() {
392 #[pin_project(Replace)]
393 pub struct PublicStruct<T> {
394 #[pin]
395 inner: PrivateStruct<T>,
396 }
397
398 struct PrivateStruct<T>(T);
399}
400
401#[test]
402fn lifetime_project() {
403 #[pin_project(Replace)]
404 struct Struct1<T, U> {
405 #[pin]
406 pinned: T,
407 unpinned: U,
408 }
409
410 #[pin_project(Replace)]
411 struct Struct2<'a, T, U> {
412 #[pin]
413 pinned: &'a mut T,
414 unpinned: U,
415 }
416
Haibo Huang2960bb32020-05-18 15:51:06 -0700417 #[pin_project(Replace, project = EnumProj, project_ref = EnumProjRef)]
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700418 enum Enum<T, U> {
419 Variant {
420 #[pin]
421 pinned: T,
422 unpinned: U,
423 },
424 }
425
426 impl<T, U> Struct1<T, U> {
427 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
428 self.project_ref().pinned
429 }
430 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
431 self.project().pinned
432 }
433 }
434
435 impl<'b, T, U> Struct2<'b, T, U> {
436 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a &'b mut T> {
437 self.project_ref().pinned
438 }
439 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut &'b mut T> {
440 self.project().pinned
441 }
442 }
443
444 impl<T, U> Enum<T, U> {
445 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
446 match self.project_ref() {
Haibo Huang2960bb32020-05-18 15:51:06 -0700447 EnumProjRef::Variant { pinned, .. } => pinned,
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700448 }
449 }
450 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
451 match self.project() {
Haibo Huang2960bb32020-05-18 15:51:06 -0700452 EnumProj::Variant { pinned, .. } => pinned,
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700453 }
454 }
455 }
456}
457
458#[rustversion::since(1.36)] // https://github.com/rust-lang/rust/pull/61207
459#[test]
460fn lifetime_project_elided() {
461 #[pin_project(Replace)]
462 struct Struct1<T, U> {
463 #[pin]
464 pinned: T,
465 unpinned: U,
466 }
467
468 #[pin_project(Replace)]
469 struct Struct2<'a, T, U> {
470 #[pin]
471 pinned: &'a mut T,
472 unpinned: U,
473 }
474
Haibo Huang2960bb32020-05-18 15:51:06 -0700475 #[pin_project(Replace, project = EnumProj, project_ref = EnumProjRef)]
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700476 enum Enum<T, U> {
477 Variant {
478 #[pin]
479 pinned: T,
480 unpinned: U,
481 },
482 }
483
484 impl<T, U> Struct1<T, U> {
485 fn get_pin_ref(self: Pin<&Self>) -> Pin<&T> {
486 self.project_ref().pinned
487 }
488 fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
489 self.project().pinned
490 }
491 }
492
493 impl<'b, T, U> Struct2<'b, T, U> {
494 fn get_pin_ref(self: Pin<&Self>) -> Pin<&&'b mut T> {
495 self.project_ref().pinned
496 }
497 fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut &'b mut T> {
498 self.project().pinned
499 }
500 }
501
502 impl<T, U> Enum<T, U> {
503 fn get_pin_ref(self: Pin<&Self>) -> Pin<&T> {
504 match self.project_ref() {
Haibo Huang2960bb32020-05-18 15:51:06 -0700505 EnumProjRef::Variant { pinned, .. } => pinned,
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700506 }
507 }
508 fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
509 match self.project() {
Haibo Huang2960bb32020-05-18 15:51:06 -0700510 EnumProj::Variant { pinned, .. } => pinned,
Chih-Hung Hsieh6f3e9272020-05-13 16:08:03 -0700511 }
512 }
513 }
514}
515
516mod visibility {
517 use pin_project::pin_project;
518
519 #[pin_project(Replace)]
520 pub(crate) struct A {
521 pub b: u8,
522 }
523}
524
525#[test]
526fn visibility() {
527 let mut x = visibility::A { b: 0 };
528 let x = Pin::new(&mut x);
529 let y = x.as_ref().project_ref();
530 let _: &u8 = y.b;
531 let y = x.project();
532 let _: &mut u8 = y.b;
533}
534
535#[test]
536fn trivial_bounds() {
537 #[pin_project(Replace)]
538 pub struct NoGenerics {
539 #[pin]
540 field: PhantomPinned,
541 }
542}
543
544#[test]
545fn dst() {
546 #[pin_project]
547 struct Struct1<T: ?Sized> {
548 x: T,
549 }
550
551 let mut x = Struct1 { x: 0_u8 };
552 let x: Pin<&mut Struct1<dyn core::fmt::Debug>> = Pin::new(&mut x as _);
553 let _y: &mut (dyn core::fmt::Debug) = x.project().x;
554
555 #[pin_project]
556 struct Struct2<T: ?Sized> {
557 #[pin]
558 x: T,
559 }
560
561 let mut x = Struct2 { x: 0_u8 };
562 let x: Pin<&mut Struct2<dyn core::fmt::Debug + Unpin>> = Pin::new(&mut x as _);
563 let _y: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().x;
564
565 #[pin_project(UnsafeUnpin)]
566 struct Struct5<T: ?Sized> {
567 x: T,
568 }
569
570 #[pin_project(UnsafeUnpin)]
571 struct Struct6<T: ?Sized> {
572 #[pin]
573 x: T,
574 }
575
576 #[pin_project(PinnedDrop)]
577 struct Struct7<T: ?Sized> {
578 x: T,
579 }
580
581 #[pinned_drop]
582 impl<T: ?Sized> PinnedDrop for Struct7<T> {
583 fn drop(self: Pin<&mut Self>) {}
584 }
585
586 #[pin_project(PinnedDrop)]
587 struct Struct8<T: ?Sized> {
588 #[pin]
589 x: T,
590 }
591
592 #[pinned_drop]
593 impl<T: ?Sized> PinnedDrop for Struct8<T> {
594 fn drop(self: Pin<&mut Self>) {}
595 }
596
597 #[pin_project(!Unpin)]
598 struct Struct9<T: ?Sized> {
599 x: T,
600 }
601
602 #[pin_project(!Unpin)]
603 struct Struct10<T: ?Sized> {
604 #[pin]
605 x: T,
606 }
607
608 #[pin_project]
609 struct TupleStruct1<T: ?Sized>(T);
610
611 #[pin_project]
612 struct TupleStruct2<T: ?Sized>(#[pin] T);
613
614 #[pin_project(UnsafeUnpin)]
615 struct TupleStruct5<T: ?Sized>(T);
616
617 #[pin_project(UnsafeUnpin)]
618 struct TupleStruct6<T: ?Sized>(#[pin] T);
619
620 #[pin_project(PinnedDrop)]
621 struct TupleStruct7<T: ?Sized>(T);
622
623 #[pinned_drop]
624 impl<T: ?Sized> PinnedDrop for TupleStruct7<T> {
625 fn drop(self: Pin<&mut Self>) {}
626 }
627
628 #[pin_project(PinnedDrop)]
629 struct TupleStruct8<T: ?Sized>(#[pin] T);
630
631 #[pinned_drop]
632 impl<T: ?Sized> PinnedDrop for TupleStruct8<T> {
633 fn drop(self: Pin<&mut Self>) {}
634 }
635
636 #[pin_project(!Unpin)]
637 struct TupleStruct9<T: ?Sized>(T);
638
639 #[pin_project(!Unpin)]
640 struct TupleStruct10<T: ?Sized>(#[pin] T);
641}
642
643#[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
644#[test]
645fn unsized_in_where_clause() {
646 #[pin_project]
647 struct Struct3<T>
648 where
649 T: ?Sized,
650 {
651 x: T,
652 }
653
654 #[pin_project]
655 struct Struct4<T>
656 where
657 T: ?Sized,
658 {
659 #[pin]
660 x: T,
661 }
662
663 #[pin_project]
664 struct TupleStruct3<T>(T)
665 where
666 T: ?Sized;
667
668 #[pin_project]
669 struct TupleStruct4<T>(#[pin] T)
670 where
671 T: ?Sized;
672}
673
674#[test]
675fn dyn_type() {
676 #[pin_project]
677 struct Struct1 {
678 f: dyn core::fmt::Debug,
679 }
680
681 #[pin_project]
682 struct Struct2 {
683 #[pin]
684 f: dyn core::fmt::Debug,
685 }
686
687 #[pin_project]
688 struct Struct3 {
689 f: dyn core::fmt::Debug + Send,
690 }
691
692 #[pin_project]
693 struct Struct4 {
694 #[pin]
695 f: dyn core::fmt::Debug + Send,
696 }
697
698 #[pin_project]
699 struct TupleStruct1(dyn core::fmt::Debug);
700
701 #[pin_project]
702 struct TupleStruct2(#[pin] dyn core::fmt::Debug);
703
704 #[pin_project]
705 struct TupleStruct3(dyn core::fmt::Debug + Send);
706
707 #[pin_project]
708 struct TupleStruct4(#[pin] dyn core::fmt::Debug + Send);
709}
710
711#[test]
712fn self_in_where_clause() {
713 pub trait Trait1 {}
714
715 #[pin_project(Replace)]
716 pub struct Struct1<T>
717 where
718 Self: Trait1,
719 {
720 x: T,
721 }
722
723 impl<T> Trait1 for Struct1<T> {}
724
725 pub trait Trait2 {
726 type Assoc;
727 }
728
729 #[pin_project(Replace)]
730 pub struct Struct2<T>
731 where
732 Self: Trait2<Assoc = Struct1<T>>,
733 <Self as Trait2>::Assoc: Trait1,
734 {
735 x: T,
736 }
737
738 impl<T> Trait2 for Struct2<T> {
739 type Assoc = Struct1<T>;
740 }
741}
742
743#[test]
744fn no_infer_outlives() {
745 trait Bar<X> {
746 type Y;
747 }
748
749 struct Example<A>(A);
750
751 impl<X, T> Bar<X> for Example<T> {
752 type Y = Option<T>;
753 }
754
755 #[pin_project(Replace)]
756 struct Foo<A, B> {
757 _x: <Example<A> as Bar<B>>::Y,
758 }
759}
760
761// https://github.com/rust-lang/rust/issues/47949
762// https://github.com/taiki-e/pin-project/pull/194#discussion_r419098111
763#[test]
764fn project_replace_panic() {
765 use std::panic;
766
767 #[pin_project(Replace)]
768 struct S<T, U> {
769 #[pin]
770 pinned: T,
771 unpinned: U,
772 }
773
774 struct D<'a>(&'a mut bool, bool);
775 impl Drop for D<'_> {
776 fn drop(&mut self) {
777 *self.0 = true;
778 if self.1 {
779 panic!()
780 }
781 }
782 }
783
784 let (mut a, mut b, mut c, mut d) = (false, false, false, false);
785 let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
786 let mut x = S { pinned: D(&mut a, true), unpinned: D(&mut b, false) };
787 let _y = Pin::new(&mut x)
788 .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) });
789 // Previous `x.pinned` was dropped and panicked when `project_replace` is called, so this is unreachable.
790 unreachable!();
791 }));
792 assert!(res.is_err());
793 assert!(a);
794 assert!(b);
795 assert!(c);
796 assert!(d);
797
798 let (mut a, mut b, mut c, mut d) = (false, false, false, false);
799 let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
800 let mut x = S { pinned: D(&mut a, false), unpinned: D(&mut b, true) };
801 {
802 let _y = Pin::new(&mut x)
803 .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) });
804 // `_y` (previous `x.unpinned`) live to the end of this scope, so this is not unreachable,
805 // unreachable!();
806 }
807 unreachable!();
808 }));
809 assert!(res.is_err());
810 assert!(a);
811 assert!(b);
812 assert!(c);
813 assert!(d);
814}