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

liballoc: introduce String, Vec const-slicing #128399

Merged
merged 1 commit into from
Oct 7, 2024
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/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
#![feature(const_option)]
#![feature(const_pin)]
#![feature(const_size_of_val)]
#![feature(const_vec_string_slice)]
#![feature(core_intrinsics)]
#![feature(deprecated_suggestion)]
#![feature(deref_pure_trait)]
Expand Down
12 changes: 6 additions & 6 deletions library/alloc/src/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ impl<T, A: Allocator> RawVec<T, A> {
/// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
/// be careful.
#[inline]
pub fn ptr(&self) -> *mut T {
pub const fn ptr(&self) -> *mut T {
self.inner.ptr()
}

Expand All @@ -293,7 +293,7 @@ impl<T, A: Allocator> RawVec<T, A> {
///
/// This will always be `usize::MAX` if `T` is zero-sized.
#[inline]
pub fn capacity(&self) -> usize {
pub const fn capacity(&self) -> usize {
self.inner.capacity(size_of::<T>())
}

Expand Down Expand Up @@ -488,17 +488,17 @@ impl<A: Allocator> RawVecInner<A> {
}

#[inline]
fn ptr<T>(&self) -> *mut T {
const fn ptr<T>(&self) -> *mut T {
self.non_null::<T>().as_ptr()
}

#[inline]
fn non_null<T>(&self) -> NonNull<T> {
self.ptr.cast().into()
const fn non_null<T>(&self) -> NonNull<T> {
self.ptr.cast().as_non_null_ptr()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Mark fn non_null const, just replace .into() with .as_non_null_ptr() (source). Then fn ptr can be marked const without changing its implementation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, not sure why GH put this comment on an empty line but it's meant to go with the ptr and non_null functions.

Anyway, this change plus the safety comments Oli requested and we can merge this.


#[inline]
fn capacity(&self, elem_size: usize) -> usize {
const fn capacity(&self, elem_size: usize) -> usize {
if elem_size == 0 { usize::MAX } else { self.cap.0 }
}

Expand Down
38 changes: 25 additions & 13 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,8 @@ impl String {
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_bytes(self) -> Vec<u8> {
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn into_bytes(self) -> Vec<u8> {
self.vec
}

Expand All @@ -1076,8 +1077,11 @@ impl String {
#[must_use]
#[stable(feature = "string_as_str", since = "1.7.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")]
pub fn as_str(&self) -> &str {
self
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_str(&self) -> &str {
// SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
// at construction.
unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
tgross35 marked this conversation as resolved.
Show resolved Hide resolved
}

/// Converts a `String` into a mutable string slice.
Expand All @@ -1096,8 +1100,11 @@ impl String {
#[must_use]
#[stable(feature = "string_as_str", since = "1.7.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")]
pub fn as_mut_str(&mut self) -> &mut str {
self
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_mut_str(&mut self) -> &mut str {
// SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
// at construction.
unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
tgross35 marked this conversation as resolved.
Show resolved Hide resolved
}

/// Appends a given string slice onto the end of this `String`.
Expand Down Expand Up @@ -1168,7 +1175,8 @@ impl String {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn capacity(&self) -> usize {
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn capacity(&self) -> usize {
self.vec.capacity()
}

Expand Down Expand Up @@ -1431,8 +1439,9 @@ impl String {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_bytes(&self) -> &[u8] {
&self.vec
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_bytes(&self) -> &[u8] {
self.vec.as_slice()
}

/// Shortens this `String` to the specified length.
Expand Down Expand Up @@ -1784,7 +1793,8 @@ impl String {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
&mut self.vec
}

Expand All @@ -1805,8 +1815,9 @@ impl String {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
#[rustc_confusables("length", "size")]
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.vec.len()
}

Expand All @@ -1824,7 +1835,8 @@ impl String {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}

Expand Down Expand Up @@ -2565,7 +2577,7 @@ impl ops::Deref for String {

#[inline]
fn deref(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.vec) }
self.as_str()
}
}

Expand All @@ -2576,7 +2588,7 @@ unsafe impl ops::DerefPure for String {}
impl ops::DerefMut for String {
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
self.as_mut_str()
}
}

Expand Down
55 changes: 44 additions & 11 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1240,7 +1240,8 @@ impl<T, A: Allocator> Vec<T, A> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn capacity(&self) -> usize {
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn capacity(&self) -> usize {
self.buf.capacity()
}

Expand Down Expand Up @@ -1548,8 +1549,22 @@ impl<T, A: Allocator> Vec<T, A> {
#[inline]
#[stable(feature = "vec_as_slice", since = "1.7.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")]
pub fn as_slice(&self) -> &[T] {
self
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_slice(&self) -> &[T] {
// SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size
// `len` containing properly-initialized `T`s. Data must not be mutated for the returned
// lifetime. Further, `len * mem::size_of::<T>` <= `ISIZE::MAX`, and allocation does not
// "wrap" through overflowing memory addresses.
//
// * Vec API guarantees that self.buf:
// * contains only properly-initialized items within 0..len
// * is aligned, contiguous, and valid for `len` reads
// * obeys size and address-wrapping constraints
//
// * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow-
// check ensures that it is not possible to mutably alias `self.buf` within the
// returned lifetime.
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
tgross35 marked this conversation as resolved.
Show resolved Hide resolved
}

/// Extracts a mutable slice of the entire vector.
Expand All @@ -1566,8 +1581,22 @@ impl<T, A: Allocator> Vec<T, A> {
#[inline]
#[stable(feature = "vec_as_slice", since = "1.7.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of
// size `len` containing properly-initialized `T`s. Data must not be accessed through any
// other pointer for the returned lifetime. Further, `len * mem::size_of::<T>` <=
// `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses.
//
// * Vec API guarantees that self.buf:
// * contains only properly-initialized items within 0..len
// * is aligned, contiguous, and valid for `len` reads
// * obeys size and address-wrapping constraints
//
// * We only construct references to `self.buf` through `&self` and `&mut self` methods;
// borrow-check ensures that it is not possible to construct a reference to `self.buf`
// within the returned lifetime.
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
tgross35 marked this conversation as resolved.
Show resolved Hide resolved
}

/// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
Expand Down Expand Up @@ -1622,9 +1651,10 @@ impl<T, A: Allocator> Vec<T, A> {
/// [`as_mut_ptr`]: Vec::as_mut_ptr
/// [`as_ptr`]: Vec::as_ptr
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
#[rustc_never_returns_null_ptr]
#[inline]
pub fn as_ptr(&self) -> *const T {
pub const fn as_ptr(&self) -> *const T {
// We shadow the slice method of the same name to avoid going through
// `deref`, which creates an intermediate reference.
self.buf.ptr()
Expand Down Expand Up @@ -1681,9 +1711,10 @@ impl<T, A: Allocator> Vec<T, A> {
/// [`as_mut_ptr`]: Vec::as_mut_ptr
/// [`as_ptr`]: Vec::as_ptr
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
#[rustc_never_returns_null_ptr]
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
pub const fn as_mut_ptr(&mut self) -> *mut T {
// We shadow the slice method of the same name to avoid going through
// `deref_mut`, which creates an intermediate reference.
self.buf.ptr()
Expand Down Expand Up @@ -2561,8 +2592,9 @@ impl<T, A: Allocator> Vec<T, A> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
#[rustc_confusables("length", "size")]
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.len
}

Expand All @@ -2579,7 +2611,8 @@ impl<T, A: Allocator> Vec<T, A> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")]
pub fn is_empty(&self) -> bool {
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}

Expand Down Expand Up @@ -3130,15 +3163,15 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> {

#[inline]
fn deref(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
self.as_slice()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
self.as_mut_slice()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,61 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
let mut _0: &[u8];
scope 1 (inlined <Vec<u8> as Deref>::deref) {
debug self => _1;
let mut _6: usize;
scope 2 (inlined Vec::<u8>::as_ptr) {
scope 2 (inlined Vec::<u8>::as_slice) {
debug self => _1;
let mut _2: &alloc::raw_vec::RawVec<u8>;
scope 3 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
debug self => _2;
let mut _3: &alloc::raw_vec::RawVecInner;
scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) {
debug self => _3;
scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
let mut _6: usize;
scope 3 (inlined Vec::<u8>::as_ptr) {
debug self => _1;
let mut _2: &alloc::raw_vec::RawVec<u8>;
scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
debug self => _2;
let mut _3: &alloc::raw_vec::RawVecInner;
scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) {
debug self => _3;
let mut _4: std::ptr::NonNull<u8>;
scope 6 (inlined Unique::<u8>::cast::<u8>) {
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
scope 7 (inlined NonNull::<u8>::cast::<u8>) {
debug self => _4;
scope 8 (inlined NonNull::<u8>::as_ptr) {
scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
debug self => _3;
let mut _4: std::ptr::NonNull<u8>;
scope 7 (inlined Unique::<u8>::cast::<u8>) {
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
scope 8 (inlined NonNull::<u8>::cast::<u8>) {
debug self => _4;
let mut _5: *const u8;
scope 9 (inlined NonNull::<u8>::as_ptr) {
debug self => _4;
let mut _5: *const u8;
}
}
}
}
scope 9 (inlined #[track_caller] <Unique<u8> as Into<NonNull<u8>>>::into) {
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
scope 10 (inlined <NonNull<u8> as From<Unique<u8>>>::from) {
debug ((unique: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
debug ((unique: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
scope 11 (inlined Unique::<u8>::as_non_null_ptr) {
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
}
scope 10 (inlined Unique::<u8>::as_non_null_ptr) {
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
}
}
scope 11 (inlined NonNull::<u8>::as_ptr) {
debug self => _4;
}
}
scope 12 (inlined NonNull::<u8>::as_ptr) {
debug self => _4;
}
}
}
}
scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) {
debug data => _5;
debug len => _6;
let _7: *const [u8];
scope 14 (inlined core::ub_checks::check_language_ub) {
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
scope 16 (inlined std::mem::size_of::<u8>) {
}
scope 17 (inlined align_of::<u8>) {
}
scope 18 (inlined slice_from_raw_parts::<u8>) {
scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) {
debug data => _5;
debug len => _6;
scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
debug data_pointer => _5;
debug metadata => _6;
let _7: *const [u8];
scope 13 (inlined core::ub_checks::check_language_ub) {
scope 14 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
scope 15 (inlined std::mem::size_of::<u8>) {
}
scope 16 (inlined align_of::<u8>) {
}
scope 17 (inlined slice_from_raw_parts::<u8>) {
debug data => _5;
debug len => _6;
scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
debug data_pointer => _5;
debug metadata => _6;
}
}
}
}
Expand Down
Loading
Loading