Skip to content

Commit 50959c4

Browse files
committed
alloc: add some try_* methods Rust-for-Linux needs
Based off of Rust-for-Linux/linux@487d757
1 parent c2452de commit 50959c4

File tree

8 files changed

+621
-8
lines changed

8 files changed

+621
-8
lines changed

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
#![feature(iter_zip)]
127127
#![feature(lang_items)]
128128
#![feature(layout_for_ptr)]
129+
#![feature(more_fallible_allocation_methods)]
129130
#![feature(negative_impls)]
130131
#![feature(never_type)]
131132
#![feature(nll)]

library/alloc/src/raw_vec.rs

+54-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use crate::collections::TryReserveErrorKind::*;
1919
#[cfg(test)]
2020
mod tests;
2121

22-
#[cfg(not(no_global_oom_handling))]
2322
enum AllocInit {
2423
/// The contents of the new memory are uninitialized.
2524
Uninitialized,
@@ -94,6 +93,16 @@ impl<T> RawVec<T, Global> {
9493
Self::with_capacity_in(capacity, Global)
9594
}
9695

96+
/// Tries to create a `RawVec` (on the system heap) with exactly the
97+
/// capacity and alignment requirements for a `[T; capacity]`. This is
98+
/// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is
99+
/// zero-sized. Note that if `T` is zero-sized this means you will
100+
/// *not* get a `RawVec` with the requested capacity.
101+
#[inline]
102+
pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
103+
Self::try_with_capacity_in(capacity, Global)
104+
}
105+
97106
/// Like `with_capacity`, but guarantees the buffer is zeroed.
98107
#[cfg(not(no_global_oom_handling))]
99108
#[must_use]
@@ -146,6 +155,13 @@ impl<T, A: Allocator> RawVec<T, A> {
146155
Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
147156
}
148157

158+
/// Like `try_with_capacity`, but parameterized over the choice of
159+
/// allocator for the returned `RawVec`.
160+
#[inline]
161+
pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
162+
Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
163+
}
164+
149165
/// Like `with_capacity_zeroed`, but parameterized over the choice
150166
/// of allocator for the returned `RawVec`.
151167
#[cfg(not(no_global_oom_handling))]
@@ -220,6 +236,33 @@ impl<T, A: Allocator> RawVec<T, A> {
220236
}
221237
}
222238

239+
fn try_allocate_in(
240+
capacity: usize,
241+
init: AllocInit,
242+
alloc: A,
243+
) -> Result<Self, TryReserveError> {
244+
if mem::size_of::<T>() == 0 {
245+
return Ok(Self::new_in(alloc));
246+
}
247+
248+
let layout = Layout::array::<T>(capacity)?;
249+
alloc_guard(layout.size())?;
250+
let result = match init {
251+
AllocInit::Uninitialized => alloc.allocate(layout),
252+
AllocInit::Zeroed => alloc.allocate_zeroed(layout),
253+
};
254+
let ptr = match result {
255+
Ok(ptr) => ptr,
256+
Err(_) => return Err(TryReserveErrorKind::AllocError { layout, non_exhaustive: () }),
257+
};
258+
259+
Ok(Self {
260+
ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
261+
cap: Self::capacity_from_bytes(ptr.len()),
262+
alloc,
263+
})
264+
}
265+
223266
/// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
224267
///
225268
/// # Safety
@@ -396,6 +439,16 @@ impl<T, A: Allocator> RawVec<T, A> {
396439
pub fn shrink_to_fit(&mut self, amount: usize) {
397440
handle_reserve(self.shrink(amount));
398441
}
442+
443+
/// Tries to shrink the allocation down to the specified amount. If the given amount
444+
/// is 0, actually completely deallocates.
445+
///
446+
/// # Panics
447+
///
448+
/// Panics if the given amount is *larger* than the current capacity.
449+
pub fn try_shrink_to_fit(&mut self, amount: usize) -> Result<(), TryReserveError> {
450+
self.shrink(amount)
451+
}
399452
}
400453

401454
impl<T, A: Allocator> RawVec<T, A> {

library/alloc/src/slice.rs

+96-1
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,11 @@ use core::mem::size_of;
9393
use core::ptr;
9494

9595
use crate::alloc::Allocator;
96-
#[cfg(not(no_global_oom_handling))]
9796
use crate::alloc::Global;
9897
#[cfg(not(no_global_oom_handling))]
9998
use crate::borrow::ToOwned;
10099
use crate::boxed::Box;
100+
use crate::collections::TryReserveError;
101101
use crate::vec::Vec;
102102

103103
#[unstable(feature = "slice_range", issue = "76393")]
@@ -153,6 +153,7 @@ mod hack {
153153
use core::alloc::Allocator;
154154

155155
use crate::boxed::Box;
156+
use crate::collections::TryReserveError;
156157
use crate::vec::Vec;
157158

158159
// We shouldn't add inline attribute to this since this is used in
@@ -172,13 +173,27 @@ mod hack {
172173
T::to_vec(s, alloc)
173174
}
174175

176+
#[inline]
177+
pub fn try_to_vec<T: TryConvertVec, A: Allocator>(
178+
s: &[T],
179+
alloc: A,
180+
) -> Result<Vec<T, A>, TryReserveError> {
181+
T::try_to_vec(s, alloc)
182+
}
183+
175184
#[cfg(not(no_global_oom_handling))]
176185
pub trait ConvertVec {
177186
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
178187
where
179188
Self: Sized;
180189
}
181190

191+
pub trait TryConvertVec {
192+
fn try_to_vec<A: Allocator>(s: &[Self], alloc: A) -> Result<Vec<Self, A>, TryReserveError>
193+
where
194+
Self: Sized;
195+
}
196+
182197
#[cfg(not(no_global_oom_handling))]
183198
impl<T: Clone> ConvertVec for T {
184199
#[inline]
@@ -231,6 +246,45 @@ mod hack {
231246
v
232247
}
233248
}
249+
250+
impl<T: Clone> TryConvertVec for T {
251+
#[inline]
252+
default fn try_to_vec<A: Allocator>(
253+
s: &[Self],
254+
alloc: A,
255+
) -> Result<Vec<Self, A>, TryReserveError> {
256+
struct DropGuard<'a, T, A: Allocator> {
257+
vec: &'a mut Vec<T, A>,
258+
num_init: usize,
259+
}
260+
impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
261+
#[inline]
262+
fn drop(&mut self) {
263+
// SAFETY:
264+
// items were marked initialized in the loop below
265+
unsafe {
266+
self.vec.set_len(self.num_init);
267+
}
268+
}
269+
}
270+
let mut vec = Vec::try_with_capacity_in(s.len(), alloc)?;
271+
let mut guard = DropGuard { vec: &mut vec, num_init: 0 };
272+
let slots = guard.vec.spare_capacity_mut();
273+
// .take(slots.len()) is necessary for LLVM to remove bounds checks
274+
// and has better codegen than zip.
275+
for (i, b) in s.iter().enumerate().take(slots.len()) {
276+
guard.num_init = i;
277+
slots[i].write(b.clone());
278+
}
279+
core::mem::forget(guard);
280+
// SAFETY:
281+
// the vec was allocated and initialized above to at least this length.
282+
unsafe {
283+
vec.set_len(s.len());
284+
}
285+
Ok(vec)
286+
}
287+
}
234288
}
235289

236290
#[lang = "slice_alloc"]
@@ -470,6 +524,24 @@ impl<T> [T] {
470524
self.to_vec_in(Global)
471525
}
472526

527+
/// Tries to copy `self` into a new `Vec`.
528+
///
529+
/// # Examples
530+
///
531+
/// ```
532+
/// let s = [10, 40, 30];
533+
/// let x = s.try_to_vec().unwrap();
534+
/// // Here, `s` and `x` can be modified independently.
535+
/// ```
536+
#[inline]
537+
#[unstable(feature = "more_fallible_allocation_methods", issue = "86942")]
538+
pub fn try_to_vec(&self) -> Result<Vec<T>, TryReserveError>
539+
where
540+
T: Clone,
541+
{
542+
self.try_to_vec_in(Global)
543+
}
544+
473545
/// Copies `self` into a new `Vec` with an allocator.
474546
///
475547
/// # Examples
@@ -494,6 +566,29 @@ impl<T> [T] {
494566
hack::to_vec(self, alloc)
495567
}
496568

569+
/// Tries to copy `self` into a new `Vec` with an allocator.
570+
///
571+
/// # Examples
572+
///
573+
/// ```
574+
/// #![feature(allocator_api)]
575+
///
576+
/// use std::alloc::System;
577+
///
578+
/// let s = [10, 40, 30];
579+
/// let x = s.try_to_vec_in(System).unwrap();
580+
/// // Here, `s` and `x` can be modified independently.
581+
/// ```
582+
#[inline]
583+
#[unstable(feature = "more_fallible_allocation_methods", issue = "86942")]
584+
pub fn try_to_vec_in<A: Allocator>(&self, alloc: A) -> Result<Vec<T, A>, TryReserveError>
585+
where
586+
T: Clone,
587+
{
588+
// N.B., see the `hack` module in this file for more details.
589+
hack::try_to_vec(self, alloc)
590+
}
591+
497592
/// Converts `self` into a vector without clones or allocation.
498593
///
499594
/// The resulting vector can be converted back into a box via

library/alloc/src/str.rs

+17
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use core::unicode::conversions;
3636

3737
use crate::borrow::ToOwned;
3838
use crate::boxed::Box;
39+
use crate::collections::TryReserveError;
3940
use crate::slice::{Concat, Join, SliceIndex};
4041
use crate::string::String;
4142
use crate::vec::Vec;
@@ -579,6 +580,22 @@ impl str {
579580
// make_ascii_lowercase() preserves the UTF-8 invariant.
580581
unsafe { String::from_utf8_unchecked(bytes) }
581582
}
583+
584+
/// Tries to create a `String`.
585+
///
586+
/// # Examples
587+
///
588+
/// Basic usage:
589+
///
590+
/// ```
591+
/// let s: &str = "a";
592+
/// let ss: String = s.try_to_owned().unwrap();
593+
/// ```
594+
#[inline]
595+
#[unstable(feature = "more_fallible_allocation_methods", issue = "86942")]
596+
pub fn try_to_owned(&self) -> Result<String, TryReserveError> {
597+
unsafe { Ok(String::from_utf8_unchecked(self.as_bytes().try_to_vec()?)) }
598+
}
582599
}
583600

584601
/// Converts a boxed slice of bytes to a boxed string slice without checking

library/alloc/src/sync.rs

+53-1
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ use crate::alloc::{box_free, WriteCloneIntoRaw};
3434
use crate::alloc::{AllocError, Allocator, Global, Layout};
3535
use crate::borrow::{Cow, ToOwned};
3636
use crate::boxed::Box;
37+
use crate::collections::TryReserveError;
3738
use crate::rc::is_dangling;
3839
#[cfg(not(no_global_oom_handling))]
3940
use crate::string::String;
40-
#[cfg(not(no_global_oom_handling))]
4141
use crate::vec::Vec;
4242

4343
#[cfg(test)]
@@ -1207,6 +1207,19 @@ impl<T> Arc<[T]> {
12071207
}
12081208
}
12091209

1210+
/// Tries to allocate an `ArcInner<[T]>` with the given length.
1211+
unsafe fn try_allocate_for_slice(len: usize) -> Result<*mut ArcInner<[T]>, TryReserveError> {
1212+
unsafe {
1213+
let layout = Layout::array::<T>(len)?;
1214+
Self::try_allocate_for_layout(
1215+
layout,
1216+
|l| Global.allocate(l),
1217+
|mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>,
1218+
)
1219+
.map_err(|_| TryReserveErrorKind::AllocError { layout, non_exhaustive: () })
1220+
}
1221+
}
1222+
12101223
/// Copy elements from slice into newly allocated Arc<\[T\]>
12111224
///
12121225
/// Unsafe because the caller must either take ownership or bind `T: Copy`.
@@ -1221,6 +1234,19 @@ impl<T> Arc<[T]> {
12211234
}
12221235
}
12231236

1237+
/// Tries to copy elements from slice into newly allocated Arc<\[T\]>
1238+
///
1239+
/// Unsafe because the caller must either take ownership or bind `T: Copy`.
1240+
unsafe fn try_copy_from_slice(v: &[T]) -> Result<Arc<[T]>, TryReserveError> {
1241+
unsafe {
1242+
let ptr = Self::try_allocate_for_slice(v.len())?;
1243+
1244+
ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len());
1245+
1246+
Ok(Self::from_ptr(ptr))
1247+
}
1248+
}
1249+
12241250
/// Constructs an `Arc<[T]>` from an iterator known to be of a certain size.
12251251
///
12261252
/// Behavior is undefined should the size be wrong.
@@ -2470,6 +2496,32 @@ impl<T> From<Vec<T>> for Arc<[T]> {
24702496
}
24712497
}
24722498

2499+
// Avoid `error: specializing impl repeats parameter` implementing `TryFrom`.
2500+
impl<T> Arc<[T]> {
2501+
/// Tries to allocate a reference-counted slice and move `v`'s items into it.
2502+
///
2503+
/// # Example
2504+
///
2505+
/// ```
2506+
/// # use std::sync::Arc;
2507+
/// let unique: Vec<i32> = vec![1, 2, 3];
2508+
/// let shared: Arc<[i32]> = Arc::try_from(unique).unwrap();
2509+
/// assert_eq!(&[1, 2, 3], &shared[..]);
2510+
/// ```
2511+
#[unstable(feature = "more_fallible_allocation_methods", issue = "86942")]
2512+
#[inline]
2513+
pub fn try_from_vec(mut v: Vec<T>) -> Result<Self, TryReserveError> {
2514+
unsafe {
2515+
let arc = Arc::try_copy_from_slice(&v)?;
2516+
2517+
// Allow the Vec to free its memory, but not destroy its contents
2518+
v.set_len(0);
2519+
2520+
Ok(arc)
2521+
}
2522+
}
2523+
}
2524+
24732525
#[stable(feature = "shared_from_cow", since = "1.45.0")]
24742526
impl<'a, B> From<Cow<'a, B>> for Arc<B>
24752527
where

0 commit comments

Comments
 (0)