Skip to content

Commit 6a809c7

Browse files
authored
Rollup merge of rust-lang#128399 - mammothbane:master, r=Amanieu,tgross35
liballoc: introduce String, Vec const-slicing 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`. ## Motivation This is to support simultaneous variance over ownership and constness. I have an enum type that may contain either `String` or `&str`, and I want to produce a `&str` from it in a possibly-`const` context. ```rust enum StrOrString<'s> { Str(&'s str), String(String), } impl<'s> StrOrString<'s> { const fn as_str(&self) -> &str { match self { // In a const-context, I really only expect to see this variant, but I can't switch the implementation // in some mode like #[cfg(const)] -- there has to be a single body Self::Str(s) => s, // so this is a problem, since it's not `const` Self::String(s) => s.as_str(), } } } ``` Currently `String` and `Vec` don't support this, but can without functional changes. Similar logic applies for `len`, `capacity`, `is_empty`. ## Changes The essential thing enabling this change is that `Unique::as_ptr` is `const`. This lets us convert `RawVec::ptr` -> `Vec::as_ptr` -> `Vec::as_slice` -> `String::as_str`. I had to move the `Deref` implementations into `as_{str,slice}` because `Deref` isn't `#[const_trait]`, but I would expect this change to be invisible up to inlining. I moved the `DerefMut` implementations as well for uniformity.
2 parents fee7e5e + 723693e commit 6a809c7

File tree

4 files changed

+76
-30
lines changed

4 files changed

+76
-30
lines changed

alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
#![feature(const_option)]
116116
#![feature(const_pin)]
117117
#![feature(const_size_of_val)]
118+
#![feature(const_vec_string_slice)]
118119
#![feature(core_intrinsics)]
119120
#![feature(deprecated_suggestion)]
120121
#![feature(deref_pure_trait)]

alloc/src/raw_vec.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ impl<T, A: Allocator> RawVec<T, A> {
280280
/// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
281281
/// be careful.
282282
#[inline]
283-
pub fn ptr(&self) -> *mut T {
283+
pub const fn ptr(&self) -> *mut T {
284284
self.inner.ptr()
285285
}
286286

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

@@ -488,17 +488,17 @@ impl<A: Allocator> RawVecInner<A> {
488488
}
489489

490490
#[inline]
491-
fn ptr<T>(&self) -> *mut T {
491+
const fn ptr<T>(&self) -> *mut T {
492492
self.non_null::<T>().as_ptr()
493493
}
494494

495495
#[inline]
496-
fn non_null<T>(&self) -> NonNull<T> {
497-
self.ptr.cast().into()
496+
const fn non_null<T>(&self) -> NonNull<T> {
497+
self.ptr.cast().as_non_null_ptr()
498498
}
499499

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

alloc/src/string.rs

+25-13
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,8 @@ impl String {
10591059
#[inline]
10601060
#[must_use = "`self` will be dropped if the result is not used"]
10611061
#[stable(feature = "rust1", since = "1.0.0")]
1062-
pub fn into_bytes(self) -> Vec<u8> {
1062+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1063+
pub const fn into_bytes(self) -> Vec<u8> {
10631064
self.vec
10641065
}
10651066

@@ -1076,8 +1077,11 @@ impl String {
10761077
#[must_use]
10771078
#[stable(feature = "string_as_str", since = "1.7.0")]
10781079
#[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")]
1079-
pub fn as_str(&self) -> &str {
1080-
self
1080+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1081+
pub const fn as_str(&self) -> &str {
1082+
// SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
1083+
// at construction.
1084+
unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
10811085
}
10821086

10831087
/// Converts a `String` into a mutable string slice.
@@ -1096,8 +1100,11 @@ impl String {
10961100
#[must_use]
10971101
#[stable(feature = "string_as_str", since = "1.7.0")]
10981102
#[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")]
1099-
pub fn as_mut_str(&mut self) -> &mut str {
1100-
self
1103+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1104+
pub const fn as_mut_str(&mut self) -> &mut str {
1105+
// SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
1106+
// at construction.
1107+
unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
11011108
}
11021109

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

@@ -1431,8 +1439,9 @@ impl String {
14311439
#[inline]
14321440
#[must_use]
14331441
#[stable(feature = "rust1", since = "1.0.0")]
1434-
pub fn as_bytes(&self) -> &[u8] {
1435-
&self.vec
1442+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1443+
pub const fn as_bytes(&self) -> &[u8] {
1444+
self.vec.as_slice()
14361445
}
14371446

14381447
/// Shortens this `String` to the specified length.
@@ -1784,7 +1793,8 @@ impl String {
17841793
/// ```
17851794
#[inline]
17861795
#[stable(feature = "rust1", since = "1.0.0")]
1787-
pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
1796+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1797+
pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
17881798
&mut self.vec
17891799
}
17901800

@@ -1805,8 +1815,9 @@ impl String {
18051815
#[inline]
18061816
#[must_use]
18071817
#[stable(feature = "rust1", since = "1.0.0")]
1818+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
18081819
#[rustc_confusables("length", "size")]
1809-
pub fn len(&self) -> usize {
1820+
pub const fn len(&self) -> usize {
18101821
self.vec.len()
18111822
}
18121823

@@ -1824,7 +1835,8 @@ impl String {
18241835
#[inline]
18251836
#[must_use]
18261837
#[stable(feature = "rust1", since = "1.0.0")]
1827-
pub fn is_empty(&self) -> bool {
1838+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1839+
pub const fn is_empty(&self) -> bool {
18281840
self.len() == 0
18291841
}
18301842

@@ -2589,7 +2601,7 @@ impl ops::Deref for String {
25892601

25902602
#[inline]
25912603
fn deref(&self) -> &str {
2592-
unsafe { str::from_utf8_unchecked(&self.vec) }
2604+
self.as_str()
25932605
}
25942606
}
25952607

@@ -2600,7 +2612,7 @@ unsafe impl ops::DerefPure for String {}
26002612
impl ops::DerefMut for String {
26012613
#[inline]
26022614
fn deref_mut(&mut self) -> &mut str {
2603-
unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
2615+
self.as_mut_str()
26042616
}
26052617
}
26062618

alloc/src/vec/mod.rs

+44-11
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,8 @@ impl<T, A: Allocator> Vec<T, A> {
12401240
/// ```
12411241
#[inline]
12421242
#[stable(feature = "rust1", since = "1.0.0")]
1243-
pub fn capacity(&self) -> usize {
1243+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1244+
pub const fn capacity(&self) -> usize {
12441245
self.buf.capacity()
12451246
}
12461247

@@ -1548,8 +1549,22 @@ impl<T, A: Allocator> Vec<T, A> {
15481549
#[inline]
15491550
#[stable(feature = "vec_as_slice", since = "1.7.0")]
15501551
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")]
1551-
pub fn as_slice(&self) -> &[T] {
1552-
self
1552+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1553+
pub const fn as_slice(&self) -> &[T] {
1554+
// SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size
1555+
// `len` containing properly-initialized `T`s. Data must not be mutated for the returned
1556+
// lifetime. Further, `len * mem::size_of::<T>` <= `ISIZE::MAX`, and allocation does not
1557+
// "wrap" through overflowing memory addresses.
1558+
//
1559+
// * Vec API guarantees that self.buf:
1560+
// * contains only properly-initialized items within 0..len
1561+
// * is aligned, contiguous, and valid for `len` reads
1562+
// * obeys size and address-wrapping constraints
1563+
//
1564+
// * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow-
1565+
// check ensures that it is not possible to mutably alias `self.buf` within the
1566+
// returned lifetime.
1567+
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
15531568
}
15541569

15551570
/// Extracts a mutable slice of the entire vector.
@@ -1566,8 +1581,22 @@ impl<T, A: Allocator> Vec<T, A> {
15661581
#[inline]
15671582
#[stable(feature = "vec_as_slice", since = "1.7.0")]
15681583
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")]
1569-
pub fn as_mut_slice(&mut self) -> &mut [T] {
1570-
self
1584+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
1585+
pub const fn as_mut_slice(&mut self) -> &mut [T] {
1586+
// SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of
1587+
// size `len` containing properly-initialized `T`s. Data must not be accessed through any
1588+
// other pointer for the returned lifetime. Further, `len * mem::size_of::<T>` <=
1589+
// `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses.
1590+
//
1591+
// * Vec API guarantees that self.buf:
1592+
// * contains only properly-initialized items within 0..len
1593+
// * is aligned, contiguous, and valid for `len` reads
1594+
// * obeys size and address-wrapping constraints
1595+
//
1596+
// * We only construct references to `self.buf` through `&self` and `&mut self` methods;
1597+
// borrow-check ensures that it is not possible to construct a reference to `self.buf`
1598+
// within the returned lifetime.
1599+
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
15711600
}
15721601

15731602
/// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
@@ -1624,9 +1653,10 @@ impl<T, A: Allocator> Vec<T, A> {
16241653
/// [`as_ptr`]: Vec::as_ptr
16251654
/// [`as_non_null`]: Vec::as_non_null
16261655
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
1656+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
16271657
#[rustc_never_returns_null_ptr]
16281658
#[inline]
1629-
pub fn as_ptr(&self) -> *const T {
1659+
pub const fn as_ptr(&self) -> *const T {
16301660
// We shadow the slice method of the same name to avoid going through
16311661
// `deref`, which creates an intermediate reference.
16321662
self.buf.ptr()
@@ -1685,9 +1715,10 @@ impl<T, A: Allocator> Vec<T, A> {
16851715
/// [`as_ptr`]: Vec::as_ptr
16861716
/// [`as_non_null`]: Vec::as_non_null
16871717
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
1718+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
16881719
#[rustc_never_returns_null_ptr]
16891720
#[inline]
1690-
pub fn as_mut_ptr(&mut self) -> *mut T {
1721+
pub const fn as_mut_ptr(&mut self) -> *mut T {
16911722
// We shadow the slice method of the same name to avoid going through
16921723
// `deref_mut`, which creates an intermediate reference.
16931724
self.buf.ptr()
@@ -2628,8 +2659,9 @@ impl<T, A: Allocator> Vec<T, A> {
26282659
/// ```
26292660
#[inline]
26302661
#[stable(feature = "rust1", since = "1.0.0")]
2662+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
26312663
#[rustc_confusables("length", "size")]
2632-
pub fn len(&self) -> usize {
2664+
pub const fn len(&self) -> usize {
26332665
self.len
26342666
}
26352667

@@ -2646,7 +2678,8 @@ impl<T, A: Allocator> Vec<T, A> {
26462678
/// ```
26472679
#[stable(feature = "rust1", since = "1.0.0")]
26482680
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")]
2649-
pub fn is_empty(&self) -> bool {
2681+
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
2682+
pub const fn is_empty(&self) -> bool {
26502683
self.len() == 0
26512684
}
26522685

@@ -3197,15 +3230,15 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> {
31973230

31983231
#[inline]
31993232
fn deref(&self) -> &[T] {
3200-
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
3233+
self.as_slice()
32013234
}
32023235
}
32033236

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

0 commit comments

Comments
 (0)