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