Use 'ref-cast' for safer transparent casting.

This commit is contained in:
Sergio Benitez 2020-06-28 13:23:34 -07:00
parent d89c7024ed
commit 3ced188f7d
6 changed files with 20 additions and 21 deletions

View File

@ -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" }

View File

@ -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)
}
}

View File

@ -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<UncasedStr>` into an `Uncased` without copying or allocating.
/// Converts a `Box<UncasedStr>` into an `Uncased` without copying or
/// allocating.
///
/// # Example
///
@ -76,9 +76,8 @@ impl UncasedStr {
/// ```
#[inline(always)]
pub fn into_uncased(self: Box<UncasedStr>) -> 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())

View File

@ -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) };

View File

@ -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"

View File

@ -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)
}
}