diff --git a/core/http/Cargo.toml b/core/http/Cargo.toml index 6fc2701d..661dce91 100644 --- a/core/http/Cargo.toml +++ b/core/http/Cargo.toml @@ -34,6 +34,7 @@ cookie = { version = "0.14.0", features = ["percent-encode"] } pear = "0.1" unicode-xid = "0.2" log = "0.4" +ref-cast = "1.0" [dev-dependencies] rocket = { version = "0.5.0-dev", path = "../lib" } diff --git a/core/http/src/raw_str.rs b/core/http/src/raw_str.rs index b5517e6b..0106cd60 100644 --- a/core/http/src/raw_str.rs +++ b/core/http/src/raw_str.rs @@ -5,6 +5,8 @@ use std::cmp::Ordering; use std::str::Utf8Error; use std::fmt; +use ref_cast::RefCast; + use crate::uncased::UncasedStr; /// A reference to a string inside of a raw HTTP message. @@ -50,7 +52,7 @@ use crate::uncased::UncasedStr; /// [`FromParam`]: rocket::request::FromParam /// [`FromFormValue`]: rocket::request::FromFormValue #[repr(transparent)] -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(RefCast, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct RawStr(str); impl RawStr { @@ -352,10 +354,7 @@ impl RawStr { impl<'a> From<&'a str> for &'a RawStr { #[inline(always)] fn from(string: &'a str) -> &'a RawStr { - // This is simply a `newtype`-like transformation. The `repr(C)` ensures - // that this is safe and correct. Note this exact pattern appears often - // in the standard library. - unsafe { &*(string as *const str as *const RawStr) } + RawStr::ref_cast(string) } } diff --git a/core/http/src/uncased.rs b/core/http/src/uncased.rs index de60cfae..9c04832d 100644 --- a/core/http/src/uncased.rs +++ b/core/http/src/uncased.rs @@ -10,6 +10,8 @@ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::fmt; +use ref_cast::RefCast; + /// A reference to an uncased (case-preserving) ASCII string. This is typically /// created from an `&str` as follows: /// @@ -19,8 +21,8 @@ use std::fmt; /// /// let ascii_ref: &UncasedStr = "Hello, world!".into(); /// ``` -#[repr(C)] -#[derive(Debug)] +#[derive(Debug, RefCast)] +#[repr(transparent)] pub struct UncasedStr(str); impl UncasedStr { @@ -39,10 +41,7 @@ impl UncasedStr { /// ``` #[inline(always)] pub fn new(string: &str) -> &UncasedStr { - // This is simply a `newtype`-like transformation. The `repr(C)` ensures - // that this is safe and correct. Note this exact pattern appears often - // in the standard library. - unsafe { &*(string as *const str as *const UncasedStr) } + UncasedStr::ref_cast(string) } /// Returns `self` as an `&str`. @@ -62,7 +61,8 @@ impl UncasedStr { &self.0 } - /// Converts a `Box` into an `Uncased` without copying or allocating. + /// Converts a `Box` into an `Uncased` without copying or + /// allocating. /// /// # Example /// @@ -76,9 +76,8 @@ impl UncasedStr { /// ``` #[inline(always)] pub fn into_uncased(self: Box) -> Uncased<'static> { - // This is the inverse of a `newtype`-like transformation. The `repr(C)` - // ensures that this is safe and correct. Note this exact pattern - // appears often in the standard library. + // This is the inverse of a `newtype`-like transformation. The + // `repr(transparent)` ensures that this is safe and correct. unsafe { let raw_str = Box::into_raw(self) as *mut str; Uncased::from(Box::from_raw(raw_str).into_string()) diff --git a/core/http/src/uri/origin.rs b/core/http/src/uri/origin.rs index 45962e9b..516e8589 100644 --- a/core/http/src/uri/origin.rs +++ b/core/http/src/uri/origin.rs @@ -200,9 +200,9 @@ impl<'a> Origin<'a> { // For this to be correct and safe, we need to ensure that: // // 1. No `&mut` references to `string` are created after this line. - // 2. `string` isn't dropped by `copy_of_str` is live. + // 2. `string` isn't dropped while `copy_of_str` is live. // - // These two facts can be easily verified. An `&mut` can be created + // These two facts can be easily verified. An `&mut` can't be created // because `string` isn't `mut`. Then, `string` is clearly not dropped // since it's passed in to `source`. let copy_of_str = unsafe { &*(string.as_str() as *const str) }; diff --git a/core/lib/Cargo.toml b/core/lib/Cargo.toml index aa9a8863..59f403fa 100644 --- a/core/lib/Cargo.toml +++ b/core/lib/Cargo.toml @@ -40,6 +40,7 @@ binascii = "0.1" pear = "0.1" atty = "0.2" async-trait = "0.1" +ref-cast = "1.0" [build-dependencies] yansi = "0.5" diff --git a/core/lib/src/rocket.rs b/core/lib/src/rocket.rs index 453b9124..f92fe8fd 100644 --- a/core/lib/src/rocket.rs +++ b/core/lib/src/rocket.rs @@ -8,6 +8,7 @@ use futures::future::FutureExt; use futures::stream::StreamExt; use futures::future::{Future, BoxFuture}; use tokio::sync::{mpsc, oneshot}; +use ref_cast::RefCast; use yansi::Paint; use state::Container; @@ -56,6 +57,7 @@ enum PreLaunchOp { /// A frozen view into the contents of an instance of `Rocket`. /// /// Obtained via [`Rocket::inspect()`]. +#[derive(RefCast)] #[repr(transparent)] pub struct Cargo(Rocket); @@ -150,10 +152,7 @@ impl Rocket { panic!("internal error: immutable launch state with manifest"); } - // This is simply a `newtype`-like transformation. The - // `repr(transparent)` on `Cargo` ensures that this is safe and - // correct. Note that this exact pattern appears often in `std`. - unsafe { &*(self as *const Rocket as *const Cargo) } + Cargo::ref_cast(self) } }