Skip to content

Commit bd15f54

Browse files
committed
feat: add downcast on Sleep trait
This commit adds `as_any` downcast method for the `Sleep` trait. BREAKING CHANGE: `Sleep` trait now needs `as_any` implementation
1 parent 9ed175d commit bd15f54

File tree

2 files changed

+130
-22
lines changed

2 files changed

+130
-22
lines changed

src/rt/mod.rs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@
66
//! to plug in other runtimes.
77
88
pub mod bounds;
9+
pub mod timer;
910

10-
use std::{
11-
future::Future,
12-
pin::Pin,
13-
time::{Duration, Instant},
14-
};
11+
pub use timer::*;
1512

1613
/// An executor of futures.
1714
///
@@ -38,20 +35,3 @@ pub trait Executor<Fut> {
3835
/// Place the future into the executor to be run.
3936
fn execute(&self, fut: Fut);
4037
}
41-
42-
/// A timer which provides timer-like functions.
43-
pub trait Timer {
44-
/// Return a future that resolves in `duration` time.
45-
fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>>;
46-
47-
/// Return a future that resolves at `deadline`.
48-
fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>>;
49-
50-
/// Reset a future to resolve at `new_deadline` instead.
51-
fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {
52-
*sleep = self.sleep_until(new_deadline);
53-
}
54-
}
55-
56-
/// A future returned by a `Timer`.
57-
pub trait Sleep: Send + Sync + Future<Output = ()> {}

src/rt/timer.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//! Provides a timer trait with timer-like functions
2+
//!
3+
//! Example using tokio timer:
4+
//! ```rust
5+
//! use std::{
6+
//! pin::Pin,
7+
//! task::{Context, Poll},
8+
//! time::{Duration, Instant},
9+
//! };
10+
//!
11+
//! use futures_util::Future;
12+
//! use pin_project_lite::pin_project;
13+
//! use hyper::rt::timer::{Timer, Sleep};
14+
//!
15+
//! #[derive(Clone, Debug)]
16+
//! pub struct TokioTimer;
17+
//!
18+
//! impl Timer for TokioTimer {
19+
//! fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {
20+
//! Box::pin(TokioSleep {
21+
//! inner: tokio::time::sleep(duration),
22+
//! })
23+
//! }
24+
//!
25+
//! fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>> {
26+
//! Box::pin(TokioSleep {
27+
//! inner: tokio::time::sleep_until(deadline.into()),
28+
//! })
29+
//! }
30+
//!
31+
//! fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {
32+
//! if sleep.downcast_ref::<TokioSleep>().is_some() {
33+
//! *sleep = self.sleep_until(new_deadline);
34+
//! }
35+
//! }
36+
//! }
37+
//!
38+
//! pin_project! {
39+
//! pub(crate) struct TokioSleep {
40+
//! #[pin]
41+
//! pub(crate) inner: tokio::time::Sleep,
42+
//! }
43+
//! }
44+
//!
45+
//! impl Future for TokioSleep {
46+
//! type Output = ();
47+
//!
48+
//! fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
49+
//! self.project().inner.poll(cx)
50+
//! }
51+
//! }
52+
//!
53+
//! impl Sleep for TokioSleep {}
54+
//! ````
55+
56+
use std::{
57+
any::TypeId,
58+
future::Future,
59+
pin::Pin,
60+
time::{Duration, Instant},
61+
};
62+
63+
/// A timer which provides timer-like functions.
64+
pub trait Timer {
65+
/// Return a future that resolves in `duration` time.
66+
fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>>;
67+
68+
/// Return a future that resolves at `deadline`.
69+
fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>>;
70+
71+
/// Reset a future to resolve at `new_deadline` instead.
72+
fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {
73+
*sleep = self.sleep_until(new_deadline);
74+
}
75+
}
76+
77+
/// A future returned by a `Timer`.
78+
pub trait Sleep: Send + Sync + Future<Output = ()> {
79+
#[doc(hidden)]
80+
/// This method is private and should not be implemented by downstream crate
81+
fn __type_id(&self, _: private::Sealed) -> TypeId
82+
where
83+
Self: 'static,
84+
{
85+
TypeId::of::<Self>()
86+
}
87+
}
88+
89+
impl dyn Sleep {
90+
//! This is a re-implementation of downcast methods from std::any::Any
91+
92+
/// Check whether the type is the same as `T`
93+
pub fn is<T>(&self) -> bool
94+
where
95+
T: Sleep + 'static,
96+
{
97+
self.__type_id(private::Sealed {}) == TypeId::of::<T>()
98+
}
99+
100+
/// Downcast the Sleep object to its original type
101+
pub fn downcast_ref<T>(&self) -> Option<&T>
102+
where
103+
T: Sleep + 'static,
104+
{
105+
if self.is::<T>() {
106+
unsafe { Some(&*(self as *const dyn Sleep as *const T)) }
107+
} else {
108+
None
109+
}
110+
}
111+
112+
/// Similar to `downcast_ref` but returns a mutable version instead
113+
pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
114+
where
115+
T: Sleep + 'static,
116+
{
117+
if self.is::<T>() {
118+
unsafe { Some(&mut *(self as *mut dyn Sleep as *mut T)) }
119+
} else {
120+
None
121+
}
122+
}
123+
}
124+
125+
mod private {
126+
#![allow(missing_debug_implementations)]
127+
pub struct Sealed {}
128+
}

0 commit comments

Comments
 (0)