Closed
Description
liballoc already has the following defined for Rc<str>
:
impl Rc<str> {
/// Constructs a new `Rc<str>` from a string slice.
#[doc(hidden)]
#[unstable(feature = "rustc_private",
reason = "for internal use in rustc",
issue = "0")]
pub fn __from_str(value: &str) -> Rc<str> {
unsafe {
// Allocate enough space for `RcBox<str>`.
let aligned_len = 2 + (value.len() + size_of::<usize>() - 1) / size_of::<usize>();
let vec = RawVec::<usize>::with_capacity(aligned_len);
let ptr = vec.ptr();
forget(vec);
// Initialize fields of `RcBox<str>`.
*ptr.offset(0) = 1; // strong: Cell::new(1)
*ptr.offset(1) = 1; // weak: Cell::new(1)
ptr::copy_nonoverlapping(value.as_ptr(), ptr.offset(2) as *mut u8, value.len());
// Combine the allocation address and the string length into a fat pointer to `RcBox`.
let rcbox_ptr: *mut RcBox<str> = mem::transmute([ptr as usize, value.len()]);
assert!(aligned_len * size_of::<usize>() == size_of_val(&*rcbox_ptr));
Rc { ptr: Shared::new(rcbox_ptr) }
}
}
}
but it is gated under the feature rustc_private
, which will never be stabilized.
It would be useful to provide From<str> for Rc<[T]>
and From<&str> for Rc<str>
implementations where the latter has use cases such as string interning (for example using: HashSet<Rc<str>>
).
A quick implementation would be:
impl<'a, T> From<&'a [T]> for Rc<[T]> {
/// Constructs a new `Rc<[T]>` from a shared slice [`&[T]`][slice].
/// All elements in the slice are copied and the length is exactly that of
/// the given [slice].
///
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let arr = [1, 2, 3];
/// let rc = Rc::from(arr);
/// assert_eq!(rc.as_ref(), &arr); // The elements match.
/// assert_eq!(rc.len(), arr.len()); // The length is the same.
/// ```
///
/// Using the [`Into`][Into] trait:
///
/// ```
/// use std::rc::Rc;
///
/// let arr = [1, 2, 3];
/// let rc: Rc<[u8]> = arr.as_ref().into();
/// assert_eq!(rc.as_ref(), &arr); // The elements match.
/// assert_eq!(rc.len(), arr.len()); // The length is the same.
/// ```
///
/// [Into]: ../../std/convert/trait.Into.html
/// [slice]: ../../std/primitive.slice.html
#[inline]
fn from(slice: &'a [T]) -> Self {
// Compute space to allocate for `RcBox<[T]>`.
let vptr = slice.as_ptr();
let vlen = slice.len();
let susize = size_of::<usize>();
let aligned_len = 1 + (size_of_val(slice) + susize - 1) / susize;
unsafe {
// Allocate enough space for `RcBox<[T]>`.
let vec = RawVec::<usize>::with_capacity(aligned_len);
let ptr = vec.ptr();
forget(vec);
// Initialize fields of `RcBox<[T]>`.
ptr::write(ptr, 1); // strong: Cell::new(1)
ptr::write(ptr.offset(1), 1); // weak: Cell::new(1)
ptr::copy_nonoverlapping(vptr, ptr.offset(1) as *mut T, vlen);
// Combine the allocation address and the string length into a
// fat pointer to `RcBox`.
let rcbox_ptr: *mut RcBox<[T]> = mem::transmute((ptr, vlen));
debug_assert_eq!(aligned_len * susize, size_of_val(&*rcbox_ptr));
Rc { ptr: Shared::new(rcbox_ptr) }
}
}
}
impl<'a> From<&'a str> for Rc<str> {
/// Constructs a new `Rc<str>` from a [string slice].
/// The underlying bytes are copied from it.
///
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let slice = "hello world!";
/// let rc: Rc<str> = Rc::from(slice);
/// assert_eq!(rc.as_ref(), slice); // The elements match.
/// assert_eq!(rc.len(), slice.len()); // The length is the same.
/// ```
///
/// Using the [`Into`][Into] trait:
///
/// ```
/// use std::rc::Rc;
///
/// let slice = "hello world!";
/// let rc: Rc<str> = slice.into();
/// assert_eq!(rc.as_ref(), slice); // The elements match.
/// assert_eq!(rc.len(), slice.len()); // The length is the same.
/// ```
///
/// [Into]: ../../std/convert/trait.Into.html
/// [string slice]: ../../std/primitive.str.html
fn from(value: &'a str) -> Self {
// This is safe since the input was valid utf8.
unsafe { mem::transmute(Rc::<[u8]>::from(value.as_bytes())) }
}
}