1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2
3 #![allow(dead_code, unreachable_pub, clippy::no_effect_underscore_binding)]
4
5 #[macro_use]
6 mod auxiliary;
7
8 use core::{
9 marker::{PhantomData, PhantomPinned},
10 pin::Pin,
11 };
12
13 use pin_project_lite::pin_project;
14
15 #[test]
projection()16 fn projection() {
17 pin_project! {
18 #[project = StructProj]
19 #[project_ref = StructProjRef]
20 #[project_replace = StructProjReplace]
21 #[derive(Default)]
22 struct Struct<T, U> {
23 #[pin]
24 f1: T,
25 f2: U,
26 }
27 }
28
29 let mut s = Struct { f1: 1, f2: 2 };
30 let mut s_orig = Pin::new(&mut s);
31 let s = s_orig.as_mut().project();
32
33 let _: Pin<&mut i32> = s.f1;
34 assert_eq!(*s.f1, 1);
35 let _: &mut i32 = s.f2;
36 assert_eq!(*s.f2, 2);
37
38 assert_eq!(s_orig.as_ref().f1, 1);
39 assert_eq!(s_orig.as_ref().f2, 2);
40
41 let mut s = Struct { f1: 1, f2: 2 };
42 let mut s = Pin::new(&mut s);
43 {
44 let StructProj { f1, f2 } = s.as_mut().project();
45 let _: Pin<&mut i32> = f1;
46 let _: &mut i32 = f2;
47 }
48 {
49 let StructProjRef { f1, f2 } = s.as_ref().project_ref();
50 let _: Pin<&i32> = f1;
51 let _: &i32 = f2;
52 }
53
54 {
55 let StructProjReplace { f1: PhantomData, f2 } =
56 s.as_mut().project_replace(Struct::default());
57 assert_eq!(f2, 2);
58 let StructProj { f1, f2 } = s.project();
59 assert_eq!(*f1, 0);
60 assert_eq!(*f2, 0);
61 }
62
63 pin_project! {
64 #[project = EnumProj]
65 #[project_ref = EnumProjRef]
66 #[project_replace = EnumProjReplace]
67 #[derive(Eq, PartialEq, Debug)]
68 enum Enum<C, D> {
69 Struct {
70 #[pin]
71 f1: C,
72 f2: D,
73 },
74 Unit,
75 }
76 }
77
78 let mut e = Enum::Struct { f1: 1, f2: 2 };
79 let mut e = Pin::new(&mut e);
80
81 match e.as_mut().project() {
82 EnumProj::Struct { f1, f2 } => {
83 let _: Pin<&mut i32> = f1;
84 assert_eq!(*f1, 1);
85 let _: &mut i32 = f2;
86 assert_eq!(*f2, 2);
87 }
88 EnumProj::Unit => unreachable!(),
89 }
90
91 assert_eq!(&*e, &Enum::Struct { f1: 1, f2: 2 });
92
93 if let EnumProj::Struct { f1, f2 } = e.as_mut().project() {
94 let _: Pin<&mut i32> = f1;
95 assert_eq!(*f1, 1);
96 let _: &mut i32 = f2;
97 assert_eq!(*f2, 2);
98 }
99
100 if let EnumProjReplace::Struct { f1: PhantomData, f2 } = e.as_mut().project_replace(Enum::Unit)
101 {
102 assert_eq!(f2, 2);
103 }
104 }
105
106 #[test]
enum_project_set()107 fn enum_project_set() {
108 pin_project! {
109 #[project = EnumProj]
110 #[project_ref = EnumProjRef]
111 #[derive(Eq, PartialEq, Debug)]
112 enum Enum {
113 V1 { #[pin] f: u8 },
114 V2 { f: bool },
115 }
116 }
117
118 let mut e = Enum::V1 { f: 25 };
119 let mut e_orig = Pin::new(&mut e);
120 let e_proj = e_orig.as_mut().project();
121
122 match e_proj {
123 EnumProj::V1 { f } => {
124 let new_e = Enum::V2 { f: f.as_ref().get_ref() == &25 };
125 e_orig.set(new_e);
126 }
127 EnumProj::V2 { .. } => unreachable!(),
128 }
129
130 assert_eq!(e, Enum::V2 { f: true });
131 }
132
133 #[test]
where_clause()134 fn where_clause() {
135 pin_project! {
136 struct Struct<T>
137 where
138 T: Copy,
139 {
140 f: T,
141 }
142 }
143
144 pin_project! {
145 #[project = EnumProj]
146 #[project_ref = EnumProjRef]
147 enum Enum<T>
148 where
149 T: Copy,
150 {
151 V { f: T },
152 }
153 }
154 }
155
156 #[test]
where_clause_and_associated_type_field()157 fn where_clause_and_associated_type_field() {
158 pin_project! {
159 struct Struct1<I>
160 where
161 I: Iterator,
162 {
163 #[pin]
164 f1: I,
165 f2: I::Item,
166 }
167 }
168
169 pin_project! {
170 struct Struct2<I, J>
171 where
172 I: Iterator<Item = J>,
173 {
174 #[pin]
175 f1: I,
176 f2: J,
177 }
178 }
179
180 pin_project! {
181 pub struct Struct3<T>
182 where
183 T: 'static,
184 {
185 f: T,
186 }
187 }
188
189 trait Static: 'static {}
190
191 impl<T> Static for Struct3<T> {}
192
193 pin_project! {
194 #[project = EnumProj]
195 #[project_ref = EnumProjRef]
196 enum Enum<I>
197 where
198 I: Iterator,
199 {
200 V1 { #[pin] f: I },
201 V2 { f: I::Item },
202 }
203 }
204 }
205
206 #[test]
derive_copy()207 fn derive_copy() {
208 pin_project! {
209 #[derive(Clone, Copy)]
210 struct Struct<T> {
211 f: T,
212 }
213 }
214
215 fn is_copy<T: Copy>() {}
216
217 is_copy::<Struct<u8>>();
218 }
219
220 #[test]
move_out()221 fn move_out() {
222 struct NotCopy;
223
224 pin_project! {
225 struct Struct {
226 f: NotCopy,
227 }
228 }
229
230 let x = Struct { f: NotCopy };
231 let _val: NotCopy = x.f;
232
233 pin_project! {
234 #[project = EnumProj]
235 #[project_ref = EnumProjRef]
236 enum Enum {
237 V { f: NotCopy },
238 }
239 }
240
241 let x = Enum::V { f: NotCopy };
242 #[allow(clippy::infallible_destructuring_match)]
243 let _val: NotCopy = match x {
244 Enum::V { f } => f,
245 };
246 }
247
248 #[test]
trait_bounds_on_type_generics()249 fn trait_bounds_on_type_generics() {
250 pin_project! {
251 pub struct Struct1<'a, T: ?Sized> {
252 f: &'a mut T,
253 }
254 }
255
256 pin_project! {
257 pub struct Struct2<'a, T: ::core::fmt::Debug> {
258 f: &'a mut T,
259 }
260 }
261
262 pin_project! {
263 pub struct Struct3<'a, T: core::fmt::Debug> {
264 f: &'a mut T,
265 }
266 }
267
268 // pin_project! {
269 // pub struct Struct4<'a, T: core::fmt::Debug + core::fmt::Display> {
270 // f: &'a mut T,
271 // }
272 // }
273
274 // pin_project! {
275 // pub struct Struct5<'a, T: core::fmt::Debug + ?Sized> {
276 // f: &'a mut T,
277 // }
278 // }
279
280 pin_project! {
281 pub struct Struct6<'a, T: core::fmt::Debug = [u8; 16]> {
282 f: &'a mut T,
283 }
284 }
285
286 let _: Struct6<'_> = Struct6 { f: &mut [0_u8; 16] };
287
288 pin_project! {
289 pub struct Struct7<T: 'static> {
290 f: T,
291 }
292 }
293
294 trait Static: 'static {}
295
296 impl<T> Static for Struct7<T> {}
297
298 pin_project! {
299 pub struct Struct8<'a, 'b: 'a> {
300 f1: &'a u8,
301 f2: &'b u8,
302 }
303 }
304
305 pin_project! {
306 #[project = EnumProj]
307 #[project_ref = EnumProjRef]
308 enum Enum<'a, T: ?Sized> {
309 V { f: &'a mut T },
310 }
311 }
312 }
313
314 #[test]
private_type_in_public_type()315 fn private_type_in_public_type() {
316 pin_project! {
317 pub struct PublicStruct<T> {
318 #[pin]
319 inner: PrivateStruct<T>,
320 }
321 }
322
323 struct PrivateStruct<T>(T);
324 }
325
326 #[allow(clippy::needless_lifetimes)]
327 #[test]
lifetime_project()328 fn lifetime_project() {
329 pin_project! {
330 struct Struct1<T, U> {
331 #[pin]
332 pinned: T,
333 unpinned: U,
334 }
335 }
336
337 pin_project! {
338 struct Struct2<'a, T, U> {
339 #[pin]
340 pinned: &'a T,
341 unpinned: U,
342 }
343 }
344
345 pin_project! {
346 #[project = EnumProj]
347 #[project_ref = EnumProjRef]
348 enum Enum<T, U> {
349 V {
350 #[pin]
351 pinned: T,
352 unpinned: U,
353 },
354 }
355 }
356
357 impl<T, U> Struct1<T, U> {
358 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
359 self.project_ref().pinned
360 }
361 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
362 self.project().pinned
363 }
364 fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&T> {
365 self.project_ref().pinned
366 }
367 fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> {
368 self.project().pinned
369 }
370 }
371
372 impl<'b, T, U> Struct2<'b, T, U> {
373 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a &'b T> {
374 self.project_ref().pinned
375 }
376 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut &'b T> {
377 self.project().pinned
378 }
379 fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&&'b T> {
380 self.project_ref().pinned
381 }
382 fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut &'b T> {
383 self.project().pinned
384 }
385 }
386
387 impl<T, U> Enum<T, U> {
388 fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> {
389 match self.project_ref() {
390 EnumProjRef::V { pinned, .. } => pinned,
391 }
392 }
393 fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
394 match self.project() {
395 EnumProj::V { pinned, .. } => pinned,
396 }
397 }
398 fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&T> {
399 match self.project_ref() {
400 EnumProjRef::V { pinned, .. } => pinned,
401 }
402 }
403 fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> {
404 match self.project() {
405 EnumProj::V { pinned, .. } => pinned,
406 }
407 }
408 }
409 }
410
411 mod visibility {
412 use pin_project_lite::pin_project;
413
414 pin_project! {
415 pub(crate) struct S {
416 pub f: u8,
417 }
418 }
419 }
420
421 #[test]
visibility()422 fn visibility() {
423 let mut x = visibility::S { f: 0 };
424 let x = Pin::new(&mut x);
425 let y = x.as_ref().project_ref();
426 let _: &u8 = y.f;
427 let y = x.project();
428 let _: &mut u8 = y.f;
429 }
430
431 #[test]
trivial_bounds()432 fn trivial_bounds() {
433 pin_project! {
434 pub struct NoGenerics {
435 #[pin]
436 f: PhantomPinned,
437 }
438 }
439
440 assert_not_unpin!(NoGenerics);
441 }
442
443 #[test]
dst()444 fn dst() {
445 pin_project! {
446 pub struct Struct1<T: ?Sized> {
447 f: T,
448 }
449 }
450
451 let mut x = Struct1 { f: 0_u8 };
452 let x: Pin<&mut Struct1<dyn core::fmt::Debug>> = Pin::new(&mut x);
453 let _: &mut (dyn core::fmt::Debug) = x.project().f;
454
455 pin_project! {
456 pub struct Struct2<T: ?Sized> {
457 #[pin]
458 f: T,
459 }
460 }
461
462 let mut x = Struct2 { f: 0_u8 };
463 let x: Pin<&mut Struct2<dyn core::fmt::Debug + Unpin>> = Pin::new(&mut x);
464 let _: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().f;
465
466 pin_project! {
467 struct Struct3<T>
468 where
469 T: ?Sized,
470 {
471 f: T,
472 }
473 }
474
475 pin_project! {
476 struct Struct4<T>
477 where
478 T: ?Sized,
479 {
480 #[pin]
481 f: T,
482 }
483 }
484
485 pin_project! {
486 struct Struct11<'a, T: ?Sized, U: ?Sized> {
487 f1: &'a mut T,
488 f2: U,
489 }
490 }
491 }
492
493 #[test]
dyn_type()494 fn dyn_type() {
495 pin_project! {
496 struct Struct1 {
497 f: dyn core::fmt::Debug,
498 }
499 }
500
501 pin_project! {
502 struct Struct2 {
503 #[pin]
504 f: dyn core::fmt::Debug,
505 }
506 }
507
508 pin_project! {
509 struct Struct3 {
510 f: dyn core::fmt::Debug + Send,
511 }
512 }
513
514 pin_project! {
515 struct Struct4 {
516 #[pin]
517 f: dyn core::fmt::Debug + Send,
518 }
519 }
520 }
521
522 #[test]
no_infer_outlives()523 fn no_infer_outlives() {
524 trait Trait<X> {
525 type Y;
526 }
527
528 struct Struct1<A>(A);
529
530 impl<X, T> Trait<X> for Struct1<T> {
531 type Y = Option<T>;
532 }
533
534 pin_project! {
535 struct Struct2<A, B> {
536 _f: <Struct1<A> as Trait<B>>::Y,
537 }
538 }
539 }
540
541 // https://github.com/taiki-e/pin-project-lite/issues/31
542 #[test]
trailing_comma()543 fn trailing_comma() {
544 pub trait T {}
545
546 pin_project! {
547 pub struct S1<
548 A: T,
549 B: T,
550 > {
551 f: (A, B),
552 }
553 }
554
555 pin_project! {
556 pub struct S2<
557 A,
558 B,
559 >
560 where
561 A: T,
562 B: T,
563 {
564 f: (A, B),
565 }
566 }
567
568 pin_project! {
569 #[allow(explicit_outlives_requirements)]
570 pub struct S3<
571 'a,
572 A: 'a,
573 B: 'a,
574 > {
575 f: &'a (A, B),
576 }
577 }
578
579 // pin_project! {
580 // pub struct S4<
581 // 'a,
582 // 'b: 'a, // <-----
583 // > {
584 // f: &'a &'b (),
585 // }
586 // }
587 }
588
589 #[test]
attrs()590 fn attrs() {
591 pin_project! {
592 /// dox1
593 #[derive(Clone)]
594 #[project = StructProj]
595 #[project_ref = StructProjRef]
596 /// dox2
597 #[derive(Debug)]
598 /// dox3
599 struct Struct {
600 // TODO
601 // /// dox4
602 f: ()
603 }
604 }
605
606 pin_project! {
607 #[project = Enum1Proj]
608 #[project_ref = Enum1ProjRef]
609 enum Enum1 {
610 #[cfg(not(any()))]
611 V {
612 f: ()
613 },
614 }
615 }
616
617 pin_project! {
618 /// dox1
619 #[derive(Clone)]
620 #[project(!Unpin)]
621 #[project = Enum2Proj]
622 #[project_ref = Enum2ProjRef]
623 /// dox2
624 #[derive(Debug)]
625 /// dox3
626 enum Enum2 {
627 /// dox4
628 V1 {
629 // TODO
630 // /// dox5
631 f: ()
632 },
633 /// dox6
634 V2,
635 }
636 }
637 }
638
639 #[test]
pinned_drop()640 fn pinned_drop() {
641 pin_project! {
642 pub struct Struct1<'a> {
643 was_dropped: &'a mut bool,
644 #[pin]
645 field: u8,
646 }
647 impl PinnedDrop for Struct1<'_> {
648 fn drop(this: Pin<&mut Self>) {
649 **this.project().was_dropped = true;
650 }
651 }
652 }
653
654 let mut was_dropped = false;
655 drop(Struct1 { was_dropped: &mut was_dropped, field: 42 });
656 assert!(was_dropped);
657
658 pin_project! {
659 pub struct Struct2<'a> {
660 was_dropped: &'a mut bool,
661 #[pin]
662 field: u8,
663 }
664 impl PinnedDrop for Struct2<'_> {
665 fn drop(mut this: Pin<&mut Self>) {
666 **this.as_mut().project().was_dropped = true;
667 }
668 }
669 }
670
671 trait Service<Request> {
672 type Error;
673 }
674
675 pin_project! {
676 struct Struct3<'a, T, Request>
677 where
678 T: Service<Request>,
679 T::Error: std::error::Error,
680 {
681 was_dropped: &'a mut bool,
682 #[pin]
683 field: T,
684 req: Request,
685 }
686
687 /// dox1
688 impl<T, Request> PinnedDrop for Struct3<'_, T, Request>
689 where
690 T: Service<Request>,
691 T::Error: std::error::Error,
692 {
693 /// dox2
694 fn drop(mut this: Pin<&mut Self>) {
695 **this.as_mut().project().was_dropped = true;
696 }
697 }
698 }
699 }
700