From e0d7fba47ca50c52cad4b6f90f132b6fb24ff01c Mon Sep 17 00:00:00 2001 From: David Koloski Date: Tue, 10 May 2022 16:30:48 -0400 Subject: [PATCH] Replace transmute with bounded manual `Send` impl --- src/proto/h2/mod.rs | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/proto/h2/mod.rs b/src/proto/h2/mod.rs index 5857c919d1..79fce1050c 100644 --- a/src/proto/h2/mod.rs +++ b/src/proto/h2/mod.rs @@ -5,7 +5,6 @@ use http::HeaderMap; use pin_project_lite::pin_project; use std::error::Error as StdError; use std::io::{self, Cursor, IoSlice}; -use std::mem; use std::task::Context; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tracing::{debug, trace, warn}; @@ -409,15 +408,14 @@ fn h2_to_io_error(e: h2::Error) -> io::Error { } } -struct UpgradedSendStream(SendStream>>); +struct UpgradedSendStream(SendStream>); impl UpgradedSendStream where B: Buf, { unsafe fn new(inner: SendStream>) -> Self { - assert_eq!(mem::size_of::(), mem::size_of::>()); - Self(mem::transmute(inner)) + Self(inner) } fn reserve_capacity(&mut self, cnt: usize) { @@ -442,30 +440,24 @@ where } unsafe fn as_inner_unchecked(&mut self) -> &mut SendStream> { - &mut *(&mut self.0 as *mut _ as *mut _) + &mut self.0 } } -#[repr(transparent)] -struct Neutered { - _inner: B, - impossible: Impossible, -} - -enum Impossible {} - -unsafe impl Send for Neutered {} +const _: () = { + #[repr(transparent)] + struct Sendable(B); -impl Buf for Neutered { - fn remaining(&self) -> usize { - match self.impossible {} - } + unsafe impl Send for Sendable {} - fn chunk(&self) -> &[u8] { - match self.impossible {} - } - - fn advance(&mut self, _cnt: usize) { - match self.impossible {} - } -} + // Because `B` can't be sent through an `UpgradedSendStream`, we want to implement `Send` even if + // `B` is not. We can do this by only implementing `Send` on `UpgradedSendStream` if + // `SendStream>>` is also `Send`. This is better than unconditionally + // implementing it because in that case `UpgradedSendStream` would be `Send` even when + // `SendStream>` is not (for some `B: Send`). This could be the case if `SendStream` or + // `SendBuf` stopped being `Send` (even for sendable `B`). + unsafe impl Send for UpgradedSendStream + where + SendStream>>: Send, + {} +};