Skip to content

Commit

Permalink
liballoc: introduce String, Vec const-slicing
Browse files Browse the repository at this point in the history
This change `const`-qualifies many methods on Vec and String, notably
`as_slice`, `as_str`, `len`. These changes are made behind the unstable
feature flag `const_vec_string_slice` with the following tracking issue:

#129041
  • Loading branch information
mammothbane committed Sep 5, 2024
1 parent a32d4a0 commit 52f9d5d
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 149 deletions.
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
#![feature(const_pin)]
#![feature(const_refs_to_cell)]
#![feature(const_size_of_val)]
#![feature(const_vec_string_slice)]
#![feature(core_intrinsics)]
#![feature(deprecated_suggestion)]
#![feature(deref_pure_trait)]
Expand Down
10 changes: 5 additions & 5 deletions library/alloc/src/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,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 @@ -306,7 +306,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 @@ -501,8 +501,8 @@ impl<A: Allocator> RawVecInner<A> {
}

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

#[inline]
Expand All @@ -511,7 +511,7 @@ impl<A: Allocator> RawVecInner<A> {
}

#[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
28 changes: 17 additions & 11 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,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 @@ -1022,8 +1023,9 @@ impl String {
#[inline]
#[must_use]
#[stable(feature = "string_as_str", since = "1.7.0")]
pub fn as_str(&self) -> &str {
self
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
}

/// Converts a `String` into a mutable string slice.
Expand All @@ -1042,7 +1044,7 @@ impl String {
#[must_use]
#[stable(feature = "string_as_str", since = "1.7.0")]
pub fn as_mut_str(&mut self) -> &mut str {
self
unsafe { str::from_utf8_unchecked_mut(&mut self.vec) }
}

/// Appends a given string slice onto the end of this `String`.
Expand Down Expand Up @@ -1112,7 +1114,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 @@ -1375,8 +1378,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 @@ -1748,8 +1752,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 @@ -1767,7 +1772,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 @@ -2484,7 +2490,7 @@ impl ops::Deref for String {

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

Expand All @@ -2495,7 +2501,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
23 changes: 14 additions & 9 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,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 @@ -1253,8 +1254,9 @@ impl<T, A: Allocator> Vec<T, A> {
/// ```
#[inline]
#[stable(feature = "vec_as_slice", since = "1.7.0")]
pub fn as_slice(&self) -> &[T] {
self
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
}

/// Extracts a mutable slice of the entire vector.
Expand All @@ -1271,7 +1273,7 @@ impl<T, A: Allocator> Vec<T, A> {
#[inline]
#[stable(feature = "vec_as_slice", since = "1.7.0")]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}

/// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
Expand Down Expand Up @@ -1326,9 +1328,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 @@ -2262,8 +2265,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 @@ -2279,7 +2283,8 @@ impl<T, A: Allocator> Vec<T, A> {
/// assert!(!v.is_empty());
/// ```
#[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 @@ -2828,15 +2833,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,67 +5,48 @@ 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 _7: 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;
let mut _6: std::ptr::NonNull<u8>;
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>) {
scope 6 (inlined Unique::<u8>::as_ptr) {
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>) {
scope 7 (inlined NonNull::<u8>::as_ptr) {
debug self => _4;
scope 8 (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>) => _6;
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>) => _6;
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>) => _6;
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
}
let mut _5: *const u8;
}
}
}
scope 12 (inlined NonNull::<u8>::as_ptr) {
debug self => _6;
}
}
}
}
scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) {
debug data => _5;
debug len => _7;
let _8: *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 8 (inlined std::slice::from_raw_parts::<'_, u8>) {
debug data => _5;
debug len => _7;
scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
debug data_pointer => _5;
debug metadata => _7;
debug len => _6;
let _7: *const [u8];
scope 9 (inlined core::ub_checks::check_language_ub) {
scope 10 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
scope 11 (inlined std::mem::size_of::<u8>) {
}
scope 12 (inlined align_of::<u8>) {
}
scope 13 (inlined slice_from_raw_parts::<u8>) {
debug data => _5;
debug len => _6;
scope 14 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
debug data_pointer => _5;
debug metadata => _6;
}
}
}
}
Expand All @@ -76,22 +57,19 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
_2 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
StorageLive(_3);
_3 = &(((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner);
StorageLive(_6);
StorageLive(_4);
_4 = copy (((((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
_5 = copy (_4.0: *const u8);
_6 = NonNull::<u8> { pointer: copy _5 };
StorageDead(_4);
StorageDead(_6);
StorageDead(_3);
StorageDead(_2);
StorageLive(_6);
_6 = copy ((*_1).1: usize);
StorageLive(_7);
_7 = copy ((*_1).1: usize);
StorageLive(_8);
_8 = *const [u8] from (copy _5, copy _7);
_0 = &(*_8);
StorageDead(_8);
_7 = *const [u8] from (copy _5, copy _6);
_0 = &(*_7);
StorageDead(_7);
StorageDead(_6);
return;
}
}
Loading

0 comments on commit 52f9d5d

Please sign in to comment.