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