Skip to content

Commit

Permalink
io: use a sealed trait to constrain VecWithInitialized (#3450)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalyd committed Jan 21, 2021
1 parent 117fc2e commit 5b7c7d5
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 10 deletions.
9 changes: 4 additions & 5 deletions tokio/src/io/util/read_to_end.rs
@@ -1,4 +1,4 @@
use crate::io::util::vec_with_initialized::{into_read_buf_parts, VecWithInitialized};
use crate::io::util::vec_with_initialized::{into_read_buf_parts, VecU8, VecWithInitialized};
use crate::io::AsyncRead;

use pin_project_lite::pin_project;
Expand Down Expand Up @@ -28,16 +28,15 @@ pub(crate) fn read_to_end<'a, R>(reader: &'a mut R, buffer: &'a mut Vec<u8>) ->
where
R: AsyncRead + Unpin + ?Sized,
{
// SAFETY: The generic type on VecWithInitialized is &mut Vec<u8>.
ReadToEnd {
reader,
buf: unsafe { VecWithInitialized::new(buffer) },
buf: VecWithInitialized::new(buffer),
read: 0,
_pin: PhantomPinned,
}
}

pub(super) fn read_to_end_internal<V: AsMut<Vec<u8>>, R: AsyncRead + ?Sized>(
pub(super) fn read_to_end_internal<V: VecU8, R: AsyncRead + ?Sized>(
buf: &mut VecWithInitialized<V>,
mut reader: Pin<&mut R>,
num_read: &mut usize,
Expand All @@ -58,7 +57,7 @@ pub(super) fn read_to_end_internal<V: AsMut<Vec<u8>>, R: AsyncRead + ?Sized>(
/// Tries to read from the provided AsyncRead.
///
/// The length of the buffer is increased by the number of bytes read.
fn poll_read_to_end<V: AsMut<Vec<u8>>, R: AsyncRead + ?Sized>(
fn poll_read_to_end<V: VecU8, R: AsyncRead + ?Sized>(
buf: &mut VecWithInitialized<V>,
read: Pin<&mut R>,
cx: &mut Context<'_>,
Expand Down
3 changes: 1 addition & 2 deletions tokio/src/io/util/read_to_string.rs
Expand Up @@ -38,10 +38,9 @@ where
R: AsyncRead + ?Sized + Unpin,
{
let buf = mem::replace(string, String::new()).into_bytes();
// SAFETY: The generic type of the VecWithInitialized is Vec<u8>.
ReadToString {
reader,
buf: unsafe { VecWithInitialized::new(buf) },
buf: VecWithInitialized::new(buf),
output: string,
read: 0,
_pin: PhantomPinned,
Expand Down
18 changes: 15 additions & 3 deletions tokio/src/io/util/vec_with_initialized.rs
@@ -1,6 +1,19 @@
use crate::io::ReadBuf;
use std::mem::MaybeUninit;

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 {}

impl VecU8 for Vec<u8> {}
impl VecU8 for &mut Vec<u8> {}
/// This struct wraps a `Vec<u8>` or `&mut Vec<u8>`, combining it with a
/// `num_initialized`, which keeps track of the number of initialized bytes
/// in the unused capacity.
Expand Down Expand Up @@ -28,10 +41,9 @@ impl VecWithInitialized<Vec<u8>> {

impl<V> VecWithInitialized<V>
where
V: AsMut<Vec<u8>>,
V: VecU8,
{
/// Safety: The generic parameter `V` must be either `Vec<u8>` or `&mut Vec<u8>`.
pub(crate) unsafe fn new(mut vec: V) -> Self {
pub(crate) fn new(mut vec: V) -> Self {
// SAFETY: The safety invariants of vector guarantee that the bytes up
// to its length are initialized.
Self {
Expand Down

0 comments on commit 5b7c7d5

Please sign in to comment.