| 1 | use futures::future::FutureExt; |
| 2 | use std::alloc::Layout; |
| 3 | use std::future::Future; |
| 4 | use std::marker::PhantomPinned; |
| 5 | use std::pin::Pin; |
| 6 | use std::rc::Rc; |
| 7 | use std::task::{Context, Poll}; |
| 8 | use tokio_util::sync::ReusableBoxFuture; |
| 9 | |
| 10 | #[test] |
| 11 | // Clippy false positive; it's useful to be able to test the trait impls for any lifetime |
| 12 | #[allow (clippy::extra_unused_lifetimes)] |
| 13 | fn traits<'a>() { |
| 14 | fn assert_traits<T: Send + Sync + Unpin>() {} |
| 15 | // Use a type that is !Unpin |
| 16 | assert_traits::<ReusableBoxFuture<'a, PhantomPinned>>(); |
| 17 | // Use a type that is !Send + !Sync |
| 18 | assert_traits::<ReusableBoxFuture<'a, Rc<()>>>(); |
| 19 | } |
| 20 | |
| 21 | #[test] |
| 22 | fn test_different_futures() { |
| 23 | let fut = async move { 10 }; |
| 24 | // Not zero sized! |
| 25 | assert_eq!(Layout::for_value(&fut).size(), 1); |
| 26 | |
| 27 | let mut b = ReusableBoxFuture::new(fut); |
| 28 | |
| 29 | assert_eq!(b.get_pin().now_or_never(), Some(10)); |
| 30 | |
| 31 | b.try_set(async move { 20 }) |
| 32 | .unwrap_or_else(|_| panic!("incorrect size" )); |
| 33 | |
| 34 | assert_eq!(b.get_pin().now_or_never(), Some(20)); |
| 35 | |
| 36 | b.try_set(async move { 30 }) |
| 37 | .unwrap_or_else(|_| panic!("incorrect size" )); |
| 38 | |
| 39 | assert_eq!(b.get_pin().now_or_never(), Some(30)); |
| 40 | } |
| 41 | |
| 42 | #[test] |
| 43 | fn test_different_sizes() { |
| 44 | let fut1 = async move { 10 }; |
| 45 | let val = [0u32; 1000]; |
| 46 | let fut2 = async move { val[0] }; |
| 47 | let fut3 = ZeroSizedFuture {}; |
| 48 | |
| 49 | assert_eq!(Layout::for_value(&fut1).size(), 1); |
| 50 | assert_eq!(Layout::for_value(&fut2).size(), 4004); |
| 51 | assert_eq!(Layout::for_value(&fut3).size(), 0); |
| 52 | |
| 53 | let mut b = ReusableBoxFuture::new(fut1); |
| 54 | assert_eq!(b.get_pin().now_or_never(), Some(10)); |
| 55 | b.set(fut2); |
| 56 | assert_eq!(b.get_pin().now_or_never(), Some(0)); |
| 57 | b.set(fut3); |
| 58 | assert_eq!(b.get_pin().now_or_never(), Some(5)); |
| 59 | } |
| 60 | |
| 61 | struct ZeroSizedFuture {} |
| 62 | impl Future for ZeroSizedFuture { |
| 63 | type Output = u32; |
| 64 | fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<u32> { |
| 65 | Poll::Ready(5) |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | #[test] |
| 70 | fn test_zero_sized() { |
| 71 | let fut = ZeroSizedFuture {}; |
| 72 | // Zero sized! |
| 73 | assert_eq!(Layout::for_value(&fut).size(), 0); |
| 74 | |
| 75 | let mut b = ReusableBoxFuture::new(fut); |
| 76 | |
| 77 | assert_eq!(b.get_pin().now_or_never(), Some(5)); |
| 78 | assert_eq!(b.get_pin().now_or_never(), Some(5)); |
| 79 | |
| 80 | b.try_set(ZeroSizedFuture {}) |
| 81 | .unwrap_or_else(|_| panic!("incorrect size" )); |
| 82 | |
| 83 | assert_eq!(b.get_pin().now_or_never(), Some(5)); |
| 84 | assert_eq!(b.get_pin().now_or_never(), Some(5)); |
| 85 | } |
| 86 | |