Auto merge of #126877 - GrigorenkoPV:clone_to_uninit, r=dtolnay
CloneToUninit impls As per #126799. Also implements it for `Wtf8` and both versions of `os_str::Slice`. Maybe it is worth to slap `#[inline]` on some of those impls. r? `@dtolnay`
This commit is contained in:
commit
c6f81a452e
@ -36,8 +36,7 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::mem::{self, MaybeUninit};
|
||||
use crate::ptr;
|
||||
mod uninit;
|
||||
|
||||
/// A common trait for the ability to explicitly duplicate an object.
|
||||
///
|
||||
@ -248,7 +247,7 @@ pub unsafe trait CloneToUninit {
|
||||
/// * `dst` must be properly aligned.
|
||||
/// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`.
|
||||
///
|
||||
/// [valid]: ptr#safety
|
||||
/// [valid]: crate::ptr#safety
|
||||
/// [pointer metadata]: crate::ptr::metadata()
|
||||
///
|
||||
/// # Panics
|
||||
@ -272,124 +271,42 @@ pub unsafe trait CloneToUninit {
|
||||
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl<T: Clone> CloneToUninit for T {
|
||||
default unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
|
||||
// ptr::write().
|
||||
unsafe {
|
||||
// We hope the optimizer will figure out to create the cloned value in-place,
|
||||
// skipping ever storing it on the stack and the copy to the destination.
|
||||
ptr::write(dst, self.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized implementation for types that are [`Copy`], not just [`Clone`],
|
||||
// and can therefore be copied bitwise.
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl<T: Copy> CloneToUninit for T {
|
||||
#[inline]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
|
||||
// ptr::copy_nonoverlapping().
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(self, dst, 1);
|
||||
}
|
||||
// SAFETY: we're calling a specialization with the same contract
|
||||
unsafe { <T as self::uninit::CopySpec>::clone_one(self, dst) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl<T: Clone> CloneToUninit for [T] {
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
default unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
let len = self.len();
|
||||
// This is the most likely mistake to make, so check it as a debug assertion.
|
||||
debug_assert_eq!(
|
||||
len,
|
||||
dst.len(),
|
||||
"clone_to_uninit() source and destination must have equal lengths",
|
||||
);
|
||||
|
||||
// SAFETY: The produced `&mut` is valid because:
|
||||
// * The caller is obligated to provide a pointer which is valid for writes.
|
||||
// * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
|
||||
// initialization status.
|
||||
let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit<T>]) };
|
||||
|
||||
// Copy the elements
|
||||
let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
|
||||
for element_ref in self.iter() {
|
||||
// If the clone() panics, `initializing` will take care of the cleanup.
|
||||
initializing.push(element_ref.clone());
|
||||
}
|
||||
// If we reach here, then the entire slice is initialized, and we've satisfied our
|
||||
// responsibilities to the caller. Disarm the cleanup guard by forgetting it.
|
||||
mem::forget(initializing);
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: we're calling a specialization with the same contract
|
||||
unsafe { <T as self::uninit::CopySpec>::clone_slice(self, dst) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl<T: Copy> CloneToUninit for [T] {
|
||||
unsafe impl CloneToUninit for str {
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
let len = self.len();
|
||||
// This is the most likely mistake to make, so check it as a debug assertion.
|
||||
debug_assert_eq!(
|
||||
len,
|
||||
dst.len(),
|
||||
"clone_to_uninit() source and destination must have equal lengths",
|
||||
);
|
||||
|
||||
// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
|
||||
// ptr::copy_nonoverlapping().
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), len);
|
||||
}
|
||||
// SAFETY: str is just a [u8] with UTF-8 invariant
|
||||
unsafe { self.as_bytes().clone_to_uninit(dst as *mut [u8]) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
|
||||
/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
|
||||
/// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
|
||||
/// initialized, unless disarmed by forgetting.
|
||||
///
|
||||
/// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
|
||||
struct InitializingSlice<'a, T> {
|
||||
data: &'a mut [MaybeUninit<T>],
|
||||
/// Number of elements of `*self.data` that are initialized.
|
||||
initialized_len: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> InitializingSlice<'a, T> {
|
||||
#[inline]
|
||||
fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
|
||||
Self { data, initialized_len: 0 }
|
||||
}
|
||||
|
||||
/// Push a value onto the end of the initialized part of the slice.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the slice is already fully initialized.
|
||||
#[inline]
|
||||
fn push(&mut self, value: T) {
|
||||
MaybeUninit::write(&mut self.data[self.initialized_len], value);
|
||||
self.initialized_len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for InitializingSlice<'a, T> {
|
||||
#[cold] // will only be invoked on unwind
|
||||
fn drop(&mut self) {
|
||||
let initialized_slice = ptr::slice_from_raw_parts_mut(
|
||||
MaybeUninit::slice_as_mut_ptr(self.data),
|
||||
self.initialized_len,
|
||||
);
|
||||
// SAFETY:
|
||||
// * the pointer is valid because it was made from a mutable reference
|
||||
// * `initialized_len` counts the initialized elements as an invariant of this type,
|
||||
// so each of the pointed-to elements is initialized and may be dropped.
|
||||
unsafe {
|
||||
ptr::drop_in_place::<[T]>(initialized_slice);
|
||||
}
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl CloneToUninit for crate::ffi::CStr {
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants.
|
||||
// And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul).
|
||||
// The pointer metadata properly preserves the length (NUL included).
|
||||
// See: `cstr_metadata_is_length_with_nul` in tests.
|
||||
unsafe { self.to_bytes_with_nul().clone_to_uninit(dst as *mut [u8]) }
|
||||
}
|
||||
}
|
||||
|
||||
|
128
library/core/src/clone/uninit.rs
Normal file
128
library/core/src/clone/uninit.rs
Normal file
@ -0,0 +1,128 @@
|
||||
use crate::mem::{self, MaybeUninit};
|
||||
use crate::ptr;
|
||||
|
||||
/// Private specialization trait used by CloneToUninit, as per
|
||||
/// [the dev guide](https://std-dev-guide.rust-lang.org/policy/specialization.html).
|
||||
pub(super) unsafe trait CopySpec: Clone {
|
||||
unsafe fn clone_one(src: &Self, dst: *mut Self);
|
||||
unsafe fn clone_slice(src: &[Self], dst: *mut [Self]);
|
||||
}
|
||||
|
||||
unsafe impl<T: Clone> CopySpec for T {
|
||||
#[inline]
|
||||
default unsafe fn clone_one(src: &Self, dst: *mut Self) {
|
||||
// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
|
||||
// ptr::write().
|
||||
unsafe {
|
||||
// We hope the optimizer will figure out to create the cloned value in-place,
|
||||
// skipping ever storing it on the stack and the copy to the destination.
|
||||
ptr::write(dst, src.clone());
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
default unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
|
||||
let len = src.len();
|
||||
// This is the most likely mistake to make, so check it as a debug assertion.
|
||||
debug_assert_eq!(
|
||||
len,
|
||||
dst.len(),
|
||||
"clone_to_uninit() source and destination must have equal lengths",
|
||||
);
|
||||
|
||||
// SAFETY: The produced `&mut` is valid because:
|
||||
// * The caller is obligated to provide a pointer which is valid for writes.
|
||||
// * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
|
||||
// initialization status.
|
||||
let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit<T>]) };
|
||||
|
||||
// Copy the elements
|
||||
let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
|
||||
for element_ref in src {
|
||||
// If the clone() panics, `initializing` will take care of the cleanup.
|
||||
initializing.push(element_ref.clone());
|
||||
}
|
||||
// If we reach here, then the entire slice is initialized, and we've satisfied our
|
||||
// responsibilities to the caller. Disarm the cleanup guard by forgetting it.
|
||||
mem::forget(initializing);
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized implementation for types that are [`Copy`], not just [`Clone`],
|
||||
// and can therefore be copied bitwise.
|
||||
unsafe impl<T: Copy> CopySpec for T {
|
||||
#[inline]
|
||||
unsafe fn clone_one(src: &Self, dst: *mut Self) {
|
||||
// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
|
||||
// ptr::copy_nonoverlapping().
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(src, dst, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
|
||||
let len = src.len();
|
||||
// This is the most likely mistake to make, so check it as a debug assertion.
|
||||
debug_assert_eq!(
|
||||
len,
|
||||
dst.len(),
|
||||
"clone_to_uninit() source and destination must have equal lengths",
|
||||
);
|
||||
|
||||
// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
|
||||
// ptr::copy_nonoverlapping().
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
|
||||
/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
|
||||
/// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
|
||||
/// initialized, unless disarmed by forgetting.
|
||||
///
|
||||
/// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
|
||||
struct InitializingSlice<'a, T> {
|
||||
data: &'a mut [MaybeUninit<T>],
|
||||
/// Number of elements of `*self.data` that are initialized.
|
||||
initialized_len: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> InitializingSlice<'a, T> {
|
||||
#[inline]
|
||||
fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
|
||||
Self { data, initialized_len: 0 }
|
||||
}
|
||||
|
||||
/// Push a value onto the end of the initialized part of the slice.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the slice is already fully initialized.
|
||||
#[inline]
|
||||
fn push(&mut self, value: T) {
|
||||
MaybeUninit::write(&mut self.data[self.initialized_len], value);
|
||||
self.initialized_len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for InitializingSlice<'a, T> {
|
||||
#[cold] // will only be invoked on unwind
|
||||
fn drop(&mut self) {
|
||||
let initialized_slice = ptr::slice_from_raw_parts_mut(
|
||||
MaybeUninit::slice_as_mut_ptr(self.data),
|
||||
self.initialized_len,
|
||||
);
|
||||
// SAFETY:
|
||||
// * the pointer is valid because it was made from a mutable reference
|
||||
// * `initialized_len` counts the initialized elements as an invariant of this type,
|
||||
// so each of the pointed-to elements is initialized and may be dropped.
|
||||
unsafe {
|
||||
ptr::drop_in_place::<[T]>(initialized_slice);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
use core::clone::CloneToUninit;
|
||||
use core::ffi::CStr;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ptr;
|
||||
|
||||
#[test]
|
||||
#[allow(suspicious_double_ref_op)]
|
||||
@ -81,3 +83,41 @@ fn drop(&mut self) {
|
||||
drop(a);
|
||||
assert_eq!(COUNTER.load(Relaxed), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone_to_uninit_str() {
|
||||
let a = "hello";
|
||||
|
||||
let mut storage: MaybeUninit<[u8; 5]> = MaybeUninit::uninit();
|
||||
unsafe { a.clone_to_uninit(storage.as_mut_ptr() as *mut [u8] as *mut str) };
|
||||
assert_eq!(a.as_bytes(), unsafe { storage.assume_init() }.as_slice());
|
||||
|
||||
let mut b: Box<str> = "world".into();
|
||||
assert_eq!(a.len(), b.len());
|
||||
assert_ne!(a, &*b);
|
||||
unsafe { a.clone_to_uninit(ptr::from_mut::<str>(&mut b)) };
|
||||
assert_eq!(a, &*b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone_to_uninit_cstr() {
|
||||
let a = c"hello";
|
||||
|
||||
let mut storage: MaybeUninit<[u8; 6]> = MaybeUninit::uninit();
|
||||
unsafe { a.clone_to_uninit(storage.as_mut_ptr() as *mut [u8] as *mut CStr) };
|
||||
assert_eq!(a.to_bytes_with_nul(), unsafe { storage.assume_init() }.as_slice());
|
||||
|
||||
let mut b: Box<CStr> = c"world".into();
|
||||
assert_eq!(a.count_bytes(), b.count_bytes());
|
||||
assert_ne!(a, &*b);
|
||||
unsafe { a.clone_to_uninit(ptr::from_mut::<CStr>(&mut b)) };
|
||||
assert_eq!(a, &*b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cstr_metadata_is_length_with_nul() {
|
||||
let s: &CStr = c"abcdef";
|
||||
let p: *const CStr = ptr::from_ref(s);
|
||||
let bytes: *const [u8] = p as *const [u8];
|
||||
assert_eq!(s.to_bytes_with_nul().len(), bytes.len());
|
||||
}
|
||||
|
@ -3,10 +3,13 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use core::clone::CloneToUninit;
|
||||
|
||||
use crate::borrow::{Borrow, Cow};
|
||||
use crate::collections::TryReserveError;
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::ops::{self, Range};
|
||||
use crate::ptr::addr_of_mut;
|
||||
use crate::rc::Rc;
|
||||
use crate::str::FromStr;
|
||||
use crate::sync::Arc;
|
||||
@ -1261,6 +1264,16 @@ fn clone(&self) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl CloneToUninit for OsStr {
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: we're just a wrapper around a platform-specific Slice
|
||||
unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
|
||||
impl From<OsString> for Arc<OsStr> {
|
||||
/// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> by moving the [`OsString`]
|
||||
|
@ -1,4 +1,6 @@
|
||||
use super::*;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::ptr;
|
||||
|
||||
#[test]
|
||||
fn test_os_string_with_capacity() {
|
||||
@ -286,3 +288,18 @@ fn slice_surrogate_edge() {
|
||||
assert_eq!(post_crab.slice_encoded_bytes(..4), "🦀");
|
||||
assert_eq!(post_crab.slice_encoded_bytes(4..), surrogate);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_to_uninit() {
|
||||
let a = OsStr::new("hello.txt");
|
||||
|
||||
let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<OsStr>(a)];
|
||||
unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut OsStr) };
|
||||
assert_eq!(a.as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) });
|
||||
|
||||
let mut b: Box<OsStr> = OsStr::new("world.exe").into();
|
||||
assert_eq!(size_of_val::<OsStr>(a), size_of_val::<OsStr>(&b));
|
||||
assert_ne!(a, &*b);
|
||||
unsafe { a.clone_to_uninit(ptr::from_mut::<OsStr>(&mut b)) };
|
||||
assert_eq!(a, &*b);
|
||||
}
|
||||
|
@ -319,6 +319,7 @@
|
||||
// tidy-alphabetical-start
|
||||
#![feature(c_str_module)]
|
||||
#![feature(char_internals)]
|
||||
#![feature(clone_to_uninit)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(core_io_borrowed_buf)]
|
||||
#![feature(duration_constants)]
|
||||
|
@ -70,6 +70,8 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use core::clone::CloneToUninit;
|
||||
|
||||
use crate::borrow::{Borrow, Cow};
|
||||
use crate::collections::TryReserveError;
|
||||
use crate::error::Error;
|
||||
@ -3109,6 +3111,16 @@ pub fn into_path_buf(self: Box<Path>) -> PathBuf {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl CloneToUninit for Path {
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: Path is just a wrapper around OsStr
|
||||
unsafe { self.inner.clone_to_uninit(core::ptr::addr_of_mut!((*dst).inner)) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRef<OsStr> for Path {
|
||||
#[inline]
|
||||
|
@ -3,6 +3,8 @@
|
||||
use super::*;
|
||||
use crate::collections::{BTreeSet, HashSet};
|
||||
use crate::hash::DefaultHasher;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::ptr;
|
||||
|
||||
#[allow(unknown_lints, unused_macro_rules)]
|
||||
macro_rules! t (
|
||||
@ -2054,3 +2056,20 @@ fn bench_hash_path_long(b: &mut test::Bencher) {
|
||||
|
||||
black_box(hasher.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_to_uninit() {
|
||||
let a = Path::new("hello.txt");
|
||||
|
||||
let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<Path>(a)];
|
||||
unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut Path) };
|
||||
assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe {
|
||||
MaybeUninit::slice_assume_init_ref(&storage)
|
||||
});
|
||||
|
||||
let mut b: Box<Path> = Path::new("world.exe").into();
|
||||
assert_eq!(size_of_val::<Path>(a), size_of_val::<Path>(&b));
|
||||
assert_ne!(a, &*b);
|
||||
unsafe { a.clone_to_uninit(ptr::from_mut::<Path>(&mut b)) };
|
||||
assert_eq!(a, &*b);
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
//! The underlying OsString/OsStr implementation on Unix and many other
|
||||
//! systems: just a `Vec<u8>`/`[u8]`.
|
||||
|
||||
use core::clone::CloneToUninit;
|
||||
use core::ptr::addr_of_mut;
|
||||
|
||||
use crate::borrow::Cow;
|
||||
use crate::collections::TryReserveError;
|
||||
use crate::fmt::Write;
|
||||
@ -345,3 +348,13 @@ pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
|
||||
self.inner.eq_ignore_ascii_case(&other.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl CloneToUninit for Slice {
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: we're just a wrapper around [u8]
|
||||
unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
//! The underlying OsString/OsStr implementation on Windows is a
|
||||
//! wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
|
||||
use core::clone::CloneToUninit;
|
||||
use core::ptr::addr_of_mut;
|
||||
|
||||
use crate::borrow::Cow;
|
||||
use crate::collections::TryReserveError;
|
||||
use crate::rc::Rc;
|
||||
@ -268,3 +271,13 @@ pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
|
||||
self.inner.eq_ignore_ascii_case(&other.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl CloneToUninit for Slice {
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: we're just a wrapper around Wtf8
|
||||
unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,14 @@
|
||||
mod tests;
|
||||
|
||||
use core::char::{encode_utf16_raw, encode_utf8_raw};
|
||||
use core::clone::CloneToUninit;
|
||||
use core::str::next_code_point;
|
||||
|
||||
use crate::borrow::Cow;
|
||||
use crate::collections::TryReserveError;
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::iter::FusedIterator;
|
||||
use crate::ptr::addr_of_mut;
|
||||
use crate::rc::Rc;
|
||||
use crate::sync::Arc;
|
||||
use crate::sys_common::AsInner;
|
||||
@ -1046,3 +1048,13 @@ fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
0xfeu8.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "clone_to_uninit", issue = "126799")]
|
||||
unsafe impl CloneToUninit for Wtf8 {
|
||||
#[inline]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
|
||||
// SAFETY: we're just a wrapper around [u8]
|
||||
unsafe { self.bytes.clone_to_uninit(addr_of_mut!((*dst).bytes)) }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user