Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add downcast on Sleep trait #3125

Merged
merged 6 commits into from
Jul 6, 2023
Merged

Conversation

dswij
Copy link
Member

@dswij dswij commented Jan 23, 2023

closes #3027

This pr adds a downcast for the Sleep trait.

@dswij
Copy link
Member Author

dswij commented Jan 23, 2023

I'm not sure I understand #3027 completely, but I'm thinking of something like this.

Also, I noticed that there is no test for this. Am I missing something, or is this something we can add on?

@seanmonstar seanmonstar requested a review from sfackler January 23, 2023 20:04
@sfackler
Copy link
Contributor

sfackler commented Jan 24, 2023

I think it'd be a bit cleaner to implement downcasting methods directly on Sleep without requiring implementors to deal with it:

mod private {
    pub struct PrivacyToken;
}

pub trait Sleep: Send + Sync + Future<Output = ()> {
    // PrivacyToken can't be named outside of this crate, so it prevents anyone from overriding this default
    // implementation in another crate. That allows us to trust it to be correct in the downcast methods below.
    #[doc(hidden)]
    fn __private_api_type_id(&self, _: private::PrivacyToken) -> TypeId {
        TypeId::of::<Self>()
    }
}

impl dyn Sleep {
    /// Returns `true` if the sleep's type is `T`.
    pub fn is<T>(&self) -> bool
    where
        T: Sleep,
    {
        self.__private_api_type_id(private::PrivacyToken) == TypeId::of::<T>()
    }

    /// Attempts to downcast the sleep to the type `T` if it has that type.
    pub fn downcast_ref<T>(&self) -> Option<&T>
    where
        T: Sleep,
    {
        if self.is::<T>() {
            unsafe { Some(&*(self as *const dyn Sleep as *const T)) }
        } else {
            None
        }
    }

    // downcast_pin as well similarly
}

@dswij
Copy link
Member Author

dswij commented Jan 24, 2023

I think it'd be a bit cleaner to implement downcasting methods directly on Sleep without requiring implementors to deal with it

That's a good point. We can probably make Sleep a derivable sealed trait instead.

Though, TypeId::of::<T> requires T: 'static, so we might want a workaround similar to this, if we wish to go that direction.

@sfackler
Copy link
Contributor

Are there any relevant non-'static Sleep implementations?

@dswij dswij force-pushed the issue-3027 branch 2 times, most recently from fc9e8f3 to b7d56c9 Compare January 29, 2023 15:30
@dswij
Copy link
Member Author

dswij commented Jan 29, 2023

Are there any relevant non-'static Sleep implementations?

I don't think so, but we shouldn't be too concerned about it now anyways imo. I have also added some docs to it

Copy link
Member

@seanmonstar seanmonstar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks goot to me, @sfackler anything else you'd need?

src/rt/mod.rs Outdated

pub mod timer;

pub use timer::*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest this be an explicit list, just to prevent any accidents now or in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/rt/mod.rs Outdated
//! If the `runtime` feature is disabled, the types in this module can be used
//! to plug in other runtimes.

pub mod timer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps let's start with the module being private, we can always make it public later if it'd be helpful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/rt/timer.rs Outdated
/// A future returned by a `Timer`.
pub trait Sleep: Send + Sync + Future<Output = ()> {
#[doc(hidden)]
/// This method is private and should not be implemented by downstream crate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can not be implemented, not should not be implemented.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/rt/timer.rs Outdated
Comment on lines 32 to 34
//! if sleep.downcast_ref::<TokioSleep>().is_some() {
//! *sleep = self.sleep_until(new_deadline);
//! }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't make much sense to me. The whole point of downcasting is to not have to create a new timer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think I understood the issue better now. I updated the example code with an implementation of tokio::time::Sleep::reset

src/rt/timer.rs Outdated
Comment on lines 100 to 122
/// Downcast the Sleep object to its original type
pub fn downcast_ref<T>(&self) -> Option<&T>
where
T: Sleep + 'static,
{
if self.is::<T>() {
unsafe { Some(&*(self as *const dyn Sleep as *const T)) }
} else {
None
}
}

/// Similar to `downcast_ref` but returns a mutable version instead
pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
where
T: Sleep + 'static,
{
if self.is::<T>() {
unsafe { Some(&mut *(self as *mut dyn Sleep as *mut T)) }
} else {
None
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these two downcast methods are going to be too useful, since reset is working with a &mut Pin<Box<dyn Sleep>>. I think we'd probably need a pub fn downcast_pin_mut<T>(self: Pin<&mut Self>) -> Option<Pin<&mut T>> probably?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sfackler
Copy link
Contributor

I think it'd be good to update the test TokioTimer to downcast in its reset implementation to test that all of this works in practice: https://github.com/hyperium/hyper/blob/master/benches/support/tokiort.rs#L29-L44

@seanmonstar
Copy link
Member

Hey @dswij, just wanted to check if you think you'll have time to update this. No worries if you can't, just checking to reduce duplicate work. :)

@dswij
Copy link
Member Author

dswij commented Feb 24, 2023

Hey @dswij, just wanted to check if you think you'll have time to update this. No worries if you can't, just checking to reduce duplicate work. :)

Sorry for the delay, I was on a break a while ago and I haven't caught up to my backlog yet.

I'll try to take a look at this PR on the weekend 🙂

@dswij dswij force-pushed the issue-3027 branch 2 times, most recently from 4dc245c to 6858fab Compare March 13, 2023 17:24
dswij added 4 commits March 22, 2023 22:41
This commit adds `as_any` downcast method for the `Sleep` trait.

BREAKING CHANGE: `Sleep` trait now needs `as_any` implementation
@dswij dswij requested review from sfackler and seanmonstar and removed request for sfackler and seanmonstar March 22, 2023 15:36
This commit allows downcasting pinned `Sleep` object to support
implementations of `Timer::reset`.

One example where this is useful is when using `TokioSleep`, i.e.
`Sleep` provided by tokio.
@dswij
Copy link
Member Author

dswij commented Mar 22, 2023

@seanmonstar @sfackler sorry for the delay, turned out it took a while for me to get back to this.

Would you guys able to help give another round of review?

@dswij
Copy link
Member Author

dswij commented Mar 30, 2023

@seanmonstar sorry to nag, but is there anything I can do to move this forward?

@seanmonstar seanmonstar requested a review from sfackler March 30, 2023 18:44
@seanmonstar seanmonstar merged commit d92d391 into hyperium:master Jul 6, 2023
@dswij dswij deleted the issue-3027 branch July 6, 2023 14:06
0xE282B0 pushed a commit to 0xE282B0/hyper that referenced this pull request Jan 12, 2024
This commit allows downcasting pinned `Sleep` object to support
implementations of `Timer::reset`.

One example where this is useful is when using `TokioSleep`, i.e.
`Sleep` provided by tokio.

Closes hyperium#3027
0xE282B0 pushed a commit to 0xE282B0/hyper that referenced this pull request Jan 16, 2024
This commit allows downcasting pinned `Sleep` object to support
implementations of `Timer::reset`.

One example where this is useful is when using `TokioSleep`, i.e.
`Sleep` provided by tokio.

Closes hyperium#3027

Signed-off-by: Sven Pfennig <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Timer::reset can't soundly have an optimized implementation
3 participants