Skip to content
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
1 change: 1 addition & 0 deletions library/alloctests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#![feature(slice_ptr_get)]
#![feature(slice_range)]
#![feature(str_as_str)]
#![feature(str_copy_from_str)]
#![feature(strict_provenance_lints)]
#![feature(string_remove_matches)]
#![feature(string_replace_in_place)]
Expand Down
15 changes: 15 additions & 0 deletions library/alloctests/tests/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,21 @@ fn test_split_at_boundscheck() {
let _ = s.split_at(1);
}

#[test]
fn test_copy_from_str() {
let src = "Saludos";
let mut dst = "Grüße, Jürgen".to_string();
dst[..7].copy_from_str(src);
assert_eq!(dst, "Saludos, Jürgen");
}

#[test]
#[should_panic]
fn test_copy_from_str_unequal_len() {
let mut dst = "hello".to_string();
dst.copy_from_str("hi");
}

#[test]
fn test_escape_unicode() {
assert_eq!("abc".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{63}");
Expand Down
63 changes: 63 additions & 0 deletions library/core/src/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2969,6 +2969,69 @@ impl str {
me.make_ascii_lowercase()
}

/// Copies the string from `src` into `self`, using a memcpy.
///
/// The length of `src` must be the same as `self`.
///
/// # Panics
///
/// This function will panic if the two strings have different lengths.
///
/// # Examples
///
/// ```
/// #![feature(str_copy_from_str)]
/// let src = "Saludos";
/// let mut dst = String::from("Grüße, Jürgen");
///
/// // Because the strings have to be the same length,
/// // we slice the destination slice from sixteen bytes
/// // to seven. It will panic if we don't do this.
/// dst[..7].copy_from_str(src);
///
/// assert_eq!(src, "Saludos");
/// assert_eq!(dst, "Saludos, Jürgen");
/// ```
///
/// Rust enforces that there can only be one mutable reference with no
/// immutable references to a particular piece of data in a particular
/// scope. Because of this, attempting to use `copy_from_str` on a
/// single string will result in a compile failure:
///
/// ```compile_fail
/// #![feature(str_copy_from_str)]
/// let mut string = String::from("Abcde");
///
/// string[..2].copy_from_str(&string[3..]); // compile fail!
/// ```
///
/// To work around this, we can use [`split_at_mut`] to create two distinct
/// sub-slices from a string:
///
/// ```
/// #![feature(str_copy_from_str)]
/// let mut string = String::from("Abcde");
///
/// {
/// let (left, right) = string.split_at_mut(2);
/// left.copy_from_str(&right[1..]);
/// }
///
/// assert_eq!(string, "decde");
/// ```
///
/// [`split_at_mut`]: str::split_at_mut
#[doc(alias = "memcpy")]
#[inline]
#[unstable(feature = "str_copy_from_str", issue = "159841")]
#[track_caller]
pub fn copy_from_str(&mut self, src: &str) {
// SAFETY: `copy_from_slice` panics unless the lengths are equal, and copying same-length
// UTF-8 into a `str` keeps it valid UTF-8.
let me = unsafe { self.as_bytes_mut() };
me.copy_from_slice(src.as_bytes());
}

/// Returns a string slice with leading ASCII whitespace removed.
///
/// 'Whitespace' refers to the definition used by
Expand Down
Loading