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

Implement Rc/Arc conversions for string-like types #45990

Merged
merged 1 commit into from
Nov 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/libstd/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ use memchr;
use ops;
use os::raw::c_char;
use ptr;
use rc::Rc;
use slice;
use str::{self, Utf8Error};
use sync::Arc;
use sys;

/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
Expand Down Expand Up @@ -704,6 +706,42 @@ impl From<CString> for Box<CStr> {
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl From<CString> for Arc<CStr> {
#[inline]
fn from(s: CString) -> Arc<CStr> {
let arc: Arc<[u8]> = Arc::from(s.into_inner());
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl<'a> From<&'a CStr> for Arc<CStr> {
#[inline]
fn from(s: &CStr) -> Arc<CStr> {
let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
Copy link
Member

Choose a reason for hiding this comment

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

Why is this safe? What guarantees that &'a CStr outlives the resulting Arc<CStr>?

Copy link
Contributor

@Centril Centril Nov 15, 2017

Choose a reason for hiding this comment

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

Why would &'a CStr need to outlive Arc<CStr>? Arc::from does a new heap allocation and copies over all the contents of s.
The unsafe block just does Arc<[u8]> -> Arc<CStr>. This is safe since the invariants of CStr are maintained.

Copy link
Member

@BurntSushi BurntSushi Nov 15, 2017

Choose a reason for hiding this comment

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

Oh I see. I didn't realize there was a copy here. In hindsight, the Arc<[u8]> type should have told me that. And of course this impl: https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From<&'a [T]>

}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl From<CString> for Rc<CStr> {
#[inline]
fn from(s: CString) -> Rc<CStr> {
let rc: Rc<[u8]> = Rc::from(s.into_inner());
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl<'a> From<&'a CStr> for Rc<CStr> {
#[inline]
fn from(s: &CStr) -> Rc<CStr> {
let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
}
}

#[stable(feature = "default_box_extra", since = "1.17.0")]
impl Default for Box<CStr> {
fn default() -> Box<CStr> {
Expand Down Expand Up @@ -1201,6 +1239,8 @@ mod tests {
use borrow::Cow::{Borrowed, Owned};
use hash::{Hash, Hasher};
use collections::hash_map::DefaultHasher;
use rc::Rc;
use sync::Arc;

#[test]
fn c_to_rust() {
Expand Down Expand Up @@ -1337,4 +1377,21 @@ mod tests {
let boxed = <Box<CStr>>::default();
assert_eq!(boxed.to_bytes_with_nul(), &[0]);
}

#[test]
fn into_rc() {
let orig: &[u8] = b"Hello, world!\0";
let cstr = CStr::from_bytes_with_nul(orig).unwrap();
let rc: Rc<CStr> = Rc::from(cstr);
let arc: Arc<CStr> = Arc::from(cstr);

assert_eq!(&*rc, cstr);
assert_eq!(&*arc, cstr);

let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
let arc2: Arc<CStr> = Arc::from(cstr.to_owned());

assert_eq!(&*rc2, cstr);
assert_eq!(&*arc2, cstr);
}
}
58 changes: 58 additions & 0 deletions src/libstd/ffi/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use fmt;
use ops;
use cmp;
use hash::{Hash, Hasher};
use rc::Rc;
use sync::Arc;

use sys::os_str::{Buf, Slice};
use sys_common::{AsInner, IntoInner, FromInner};
Expand Down Expand Up @@ -592,6 +594,42 @@ impl From<OsString> for Box<OsStr> {
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl From<OsString> for Arc<OsStr> {
#[inline]
fn from(s: OsString) -> Arc<OsStr> {
let arc = s.inner.into_arc();
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) }
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl<'a> From<&'a OsStr> for Arc<OsStr> {
#[inline]
fn from(s: &OsStr) -> Arc<OsStr> {
let arc = s.inner.into_arc();
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) }
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl From<OsString> for Rc<OsStr> {
#[inline]
fn from(s: OsString) -> Rc<OsStr> {
let rc = s.inner.into_rc();
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) }
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl<'a> From<&'a OsStr> for Rc<OsStr> {
#[inline]
fn from(s: &OsStr) -> Rc<OsStr> {
let rc = s.inner.into_rc();
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) }
}
}

#[stable(feature = "box_default_extra", since = "1.17.0")]
impl Default for Box<OsStr> {
fn default() -> Box<OsStr> {
Expand Down Expand Up @@ -793,6 +831,9 @@ mod tests {
use super::*;
use sys_common::{AsInner, IntoInner};

use rc::Rc;
use sync::Arc;

#[test]
fn test_os_string_with_capacity() {
let os_string = OsString::with_capacity(0);
Expand Down Expand Up @@ -935,4 +976,21 @@ mod tests {
assert_eq!(os_str, os_string);
assert!(os_string.capacity() >= 123);
}

#[test]
fn into_rc() {
let orig = "Hello, world!";
let os_str = OsStr::new(orig);
let rc: Rc<OsStr> = Rc::from(os_str);
let arc: Arc<OsStr> = Arc::from(os_str);

assert_eq!(&*rc, os_str);
assert_eq!(&*arc, os_str);

let rc2: Rc<OsStr> = Rc::from(os_str.to_owned());
let arc2: Arc<OsStr> = Arc::from(os_str.to_owned());

assert_eq!(&*rc2, os_str);
assert_eq!(&*arc2, os_str);
}
}
58 changes: 58 additions & 0 deletions src/libstd/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ use hash::{Hash, Hasher};
use io;
use iter::{self, FusedIterator};
use ops::{self, Deref};
use rc::Rc;
use sync::Arc;

use ffi::{OsStr, OsString};

Expand Down Expand Up @@ -1452,6 +1454,42 @@ impl<'a> From<PathBuf> for Cow<'a, Path> {
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl From<PathBuf> for Arc<Path> {
#[inline]
fn from(s: PathBuf) -> Arc<Path> {
let arc: Arc<OsStr> = Arc::from(s.into_os_string());
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl<'a> From<&'a Path> for Arc<Path> {
#[inline]
fn from(s: &Path) -> Arc<Path> {
let arc: Arc<OsStr> = Arc::from(s.as_os_str());
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl From<PathBuf> for Rc<Path> {
#[inline]
fn from(s: PathBuf) -> Rc<Path> {
let rc: Rc<OsStr> = Rc::from(s.into_os_string());
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
}
}

#[stable(feature = "shared_from_slice2", since = "1.23.0")]
impl<'a> From<&'a Path> for Rc<Path> {
#[inline]
fn from(s: &Path) -> Rc<Path> {
let rc: Rc<OsStr> = Rc::from(s.as_os_str());
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl ToOwned for Path {
type Owned = PathBuf;
Expand Down Expand Up @@ -2568,6 +2606,9 @@ impl Error for StripPrefixError {
mod tests {
use super::*;

use rc::Rc;
use sync::Arc;

macro_rules! t(
($path:expr, iter: $iter:expr) => (
{
Expand Down Expand Up @@ -3970,4 +4011,21 @@ mod tests {
assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b");
assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b");
}

#[test]
fn into_rc() {
let orig = "hello/world";
let path = Path::new(orig);
let rc: Rc<Path> = Rc::from(path);
let arc: Arc<Path> = Arc::from(path);

assert_eq!(&*rc, path);
assert_eq!(&*arc, path);

let rc2: Rc<Path> = Rc::from(path.to_owned());
let arc2: Arc<Path> = Arc::from(path.to_owned());

assert_eq!(&*rc2, path);
assert_eq!(&*arc2, path);
}
}
24 changes: 24 additions & 0 deletions src/libstd/sys/redox/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use borrow::Cow;
use fmt;
use str;
use mem;
use rc::Rc;
use sync::Arc;
use sys_common::{AsInner, IntoInner};
use std_unicode::lossy::Utf8Lossy;

Expand Down Expand Up @@ -123,6 +125,16 @@ impl Buf {
let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
Buf { inner: inner.into_vec() }
}

#[inline]
pub fn into_arc(&self) -> Arc<Slice> {
self.as_slice().into_arc()
}

#[inline]
pub fn into_rc(&self) -> Rc<Slice> {
self.as_slice().into_rc()
}
}

impl Slice {
Expand Down Expand Up @@ -156,4 +168,16 @@ impl Slice {
let boxed: Box<[u8]> = Default::default();
unsafe { mem::transmute(boxed) }
}

#[inline]
pub fn into_arc(&self) -> Arc<Slice> {
let arc: Arc<[u8]> = Arc::from(&self.inner);
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
}

#[inline]
pub fn into_rc(&self) -> Rc<Slice> {
let rc: Rc<[u8]> = Rc::from(&self.inner);
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
}
}
24 changes: 24 additions & 0 deletions src/libstd/sys/unix/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use borrow::Cow;
use fmt;
use str;
use mem;
use rc::Rc;
use sync::Arc;
use sys_common::{AsInner, IntoInner};
use std_unicode::lossy::Utf8Lossy;

Expand Down Expand Up @@ -123,6 +125,16 @@ impl Buf {
let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
Buf { inner: inner.into_vec() }
}

#[inline]
pub fn into_arc(&self) -> Arc<Slice> {
self.as_slice().into_arc()
}

#[inline]
pub fn into_rc(&self) -> Rc<Slice> {
self.as_slice().into_rc()
}
}

impl Slice {
Expand Down Expand Up @@ -156,4 +168,16 @@ impl Slice {
let boxed: Box<[u8]> = Default::default();
unsafe { mem::transmute(boxed) }
}

#[inline]
pub fn into_arc(&self) -> Arc<Slice> {
let arc: Arc<[u8]> = Arc::from(&self.inner);
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
}

#[inline]
pub fn into_rc(&self) -> Rc<Slice> {
let rc: Rc<[u8]> = Rc::from(&self.inner);
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
}
}
24 changes: 24 additions & 0 deletions src/libstd/sys/wasm/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use borrow::Cow;
use fmt;
use str;
use mem;
use rc::Rc;
use sync::Arc;
use sys_common::{AsInner, IntoInner};
use std_unicode::lossy::Utf8Lossy;

Expand Down Expand Up @@ -123,6 +125,16 @@ impl Buf {
let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
Buf { inner: inner.into_vec() }
}

#[inline]
pub fn into_arc(&self) -> Arc<Slice> {
self.as_slice().into_arc()
}

#[inline]
pub fn into_rc(&self) -> Rc<Slice> {
self.as_slice().into_rc()
}
}

impl Slice {
Expand Down Expand Up @@ -156,4 +168,16 @@ impl Slice {
let boxed: Box<[u8]> = Default::default();
unsafe { mem::transmute(boxed) }
}

#[inline]
pub fn into_arc(&self) -> Arc<Slice> {
let arc: Arc<[u8]> = Arc::from(&self.inner);
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
}

#[inline]
pub fn into_rc(&self) -> Rc<Slice> {
let rc: Rc<[u8]> = Rc::from(&self.inner);
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
}
}
Loading