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

Use a sealed trait to constrain VecWithInitialized #3450

Merged
merged 6 commits into from Jan 21, 2021
Merged

Use a sealed trait to constrain VecWithInitialized #3450

merged 6 commits into from Jan 21, 2021

Conversation

vitalyd
Copy link
Contributor

@vitalyd vitalyd commented Jan 20, 2021

Use a sealed trait to constrain VecWithInitialized's generic type parameter. The safety of that struct relies on invariants upheld by Vec<u8>. The struct currently has an unsafe new associated fn where V: AsMut<Vec<u8>>.

Motivation

Avoids a bit of unsafe.

Solution

This PR defines a crate private VecU8 trait and implements it for Vec<u8> and &mut Vec<u8>.

cc @Darksonn as we discussed this a bit in #3426

@Darksonn Darksonn added A-tokio Area: The main tokio crate M-io Module: tokio/io labels Jan 20, 2021
Apply Darksonn's rustfmt fix (thanks!)

Co-authored-by: Alice Ryhl <alice@ryhl.io>
tokio/src/io/util/read_to_end.rs Outdated Show resolved Hide resolved
tokio/src/io/util/read_to_string.rs Outdated Show resolved Hide resolved
Comment on lines 59 to 71
pub(crate) fn get_read_buf<'a>(&'a mut self) -> ReadBuf<'a> {
pub(crate) fn get_read_buf(&mut self) -> ReadBuf<'_> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you undo this change? I'd like to keep the lifetime inside the from_raw_parts_mut call.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. This was a bit of a gratuitous change in passing 😄 . May I ask why you prefer the explicit 'a though?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's mostly that std::slice::from_raw_parts_mut detaches the lifetime of the resulting slice from the owner, and I try to avoid that as much as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, from_raw_parts_mut uses an "unbounded" lifetime param. However, inference should select the proper output lifetime when using the '_ wildcard.

But, I reverted this part.

Comment on lines +4 to +13
mod private {
pub trait Sealed {}

impl Sealed for Vec<u8> {}
impl Sealed for &mut Vec<u8> {}
}

/// A sealed trait that constrains the generic type parameter in `VecWithInitialized<V>`. That struct's safety relies
/// on certain invariants upheld by `Vec<u8>`.
pub(crate) trait VecU8: AsMut<Vec<u8>> + private::Sealed {}
Copy link
Contributor

Choose a reason for hiding this comment

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

The question is if it is better to just make the trait unsafe instead of sealing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An unsafe trait could work as well. I felt that a sealed safe trait would be a bit better in that:

  • minimizes unsafes
  • sealing and defining a controlled set of impls seemed pretty succinct and to the point

However, I'm open to hearing arguments for making it an unsafe trait instead. Either way, the thing that somewhat irked me with existing code is that we weren't capturing safety via types.

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean, either is fine. I was mostly wondering to myself if sealing even works without a crate boundary, but after some more thought, I guess it does.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it's essentially sealing from the rest of the crate. This allows specifying the valid types in the vec_with_initialized module, which is nice since it's the same source file as the uses and where the commentary about Vec's invariants lives.

vitalyd and others added 4 commits January 20, 2021 17:59
Co-authored-by: Alice Ryhl <alice@ryhl.io>
Co-authored-by: Alice Ryhl <alice@ryhl.io>
Co-authored-by: Alice Ryhl <alice@ryhl.io>
@Darksonn Darksonn merged commit 5b7c7d5 into tokio-rs:master Jan 21, 2021
@Darksonn
Copy link
Contributor

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate M-io Module: tokio/io
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants