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

Rollup of 6 pull requests #89703

Merged
merged 23 commits into from
Oct 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
853ffc7
stack overflow handler specific openbsd fix.
devnexen Jul 27, 2021
af83a96
std: Stabilize command_access
lf- Aug 28, 2021
4be574e
Add 'core::array::from_fn' and 'core::array::try_from_fn'
c410-f3r Sep 30, 2021
fdccc7d
Use reference instead of raw pointer
c410-f3r Sep 30, 2021
325025e
Improve previous commit
steffahn Sep 30, 2021
13bfcb7
Merge pull request #2 from steffahn/collect_into_array_fix_ub
c410-f3r Sep 30, 2021
355c7e9
Remove an unnecessary use of unwrap_unchecked
steffahn Sep 30, 2021
91ad91e
Skip platforms without unwinding support
c410-f3r Oct 3, 2021
5e1941c
Apply suggestions from code review
yaahc Oct 5, 2021
e159d42
Redo #81358 in unicode-table-generator
cuviper Oct 6, 2021
6b0b417
Let unicode-table-generator fail gracefully for bitsets
cuviper Oct 7, 2021
459a7e3
Regenerate tables for Unicode 14.0.0
cuviper Oct 7, 2021
6a52fb7
Add documentation to boxed conversions
timClicks Oct 8, 2021
85c4a52
Also cfg flag auxiliar function
c410-f3r Oct 8, 2021
fa5a212
Simplify wording
timClicks Oct 9, 2021
020ec0a
Remove unnecessary hyphen
timClicks Oct 9, 2021
3214253
Fix invalid HTML generation for higher bounds
GuillaumeGomez Oct 8, 2021
86bf3ce
Rollup merge of #75644 - c410-f3r:array, r=yaahc
GuillaumeGomez Oct 9, 2021
3e4f956
Rollup merge of #87528 - :stack_overflow_obsd, r=joshtriplett
GuillaumeGomez Oct 9, 2021
703cb97
Rollup merge of #88436 - lf-:stabilize-command-access, r=yaahc
GuillaumeGomez Oct 9, 2021
21a5101
Rollup merge of #89614 - cuviper:unicode-14, r=joshtriplett
GuillaumeGomez Oct 9, 2021
9f32ab8
Rollup merge of #89664 - timClicks:51430-document-boxed-conversions, …
GuillaumeGomez Oct 9, 2021
3e93472
Rollup merge of #89700 - GuillaumeGomez:fix-rustdoc-higher-bound-html…
GuillaumeGomez Oct 9, 2021
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
41 changes: 41 additions & 0 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,7 @@ impl<T> From<T> for Box<T> {
/// from the stack into it.
///
/// # Examples
///
/// ```rust
/// let x = 5;
/// let boxed = Box::new(5);
Expand Down Expand Up @@ -1330,6 +1331,12 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl<T: Copy> From<Cow<'_, [T]>> for Box<[T]> {
/// Converts a `Cow<'_, [T]>` into a `Box<[T]>`
///
/// When `cow` is the `Cow::Borrowed` variant, this
/// conversion allocates on the heap and copies the
/// underlying slice. Otherwise, it will try to reuse the owned
/// `Vec`'s allocation.
#[inline]
fn from(cow: Cow<'_, [T]>) -> Box<[T]> {
match cow {
Expand All @@ -1348,6 +1355,7 @@ impl From<&str> for Box<str> {
/// and performs a copy of `s`.
///
/// # Examples
///
/// ```rust
/// let boxed: Box<str> = Box::from("hello");
/// println!("{}", boxed);
Expand All @@ -1361,6 +1369,29 @@ impl From<&str> for Box<str> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl From<Cow<'_, str>> for Box<str> {
/// Converts a `Cow<'_, str>` into a `Box<str>`
///
/// When `cow` is the `Cow::Borrowed` variant, this
/// conversion allocates on the heap and copies the
/// underlying `str`. Otherwise, it will try to reuse the owned
/// `String`'s allocation.
///
/// # Examples
///
/// ```rust
/// use std::borrow::Cow;
///
/// let unboxed = Cow::Borrowed("hello");
/// let boxed: Box<str> = Box::from(unboxed);
/// println!("{}", boxed);
/// ```
///
/// ```rust
/// # use std::borrow::Cow;
/// let unboxed = Cow::Owned("hello".to_string());
/// let boxed: Box<str> = Box::from(unboxed);
/// println!("{}", boxed);
/// ```
#[inline]
fn from(cow: Cow<'_, str>) -> Box<str> {
match cow {
Expand Down Expand Up @@ -1403,6 +1434,7 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
/// This conversion moves the array to newly heap-allocated memory.
///
/// # Examples
///
/// ```rust
/// let boxed: Box<[u8]> = Box::from([4, 2]);
/// println!("{:?}", boxed);
Expand All @@ -1416,6 +1448,15 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
type Error = Box<[T]>;

/// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`.
///
/// The conversion occurs in-place and does not require a
/// new memory allocation.
///
/// # Errors
///
/// Returns the old `Box<[T]>` in the `Err` variant if
/// `boxed_slice.len()` does not equal `N`.
fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
if boxed_slice.len() == N {
Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) })
Expand Down
120 changes: 103 additions & 17 deletions library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,69 @@ mod iter;
#[stable(feature = "array_value_iter", since = "1.51.0")]
pub use iter::IntoIter;

/// Creates an array `[T; N]` where each array element `T` is returned by the `cb` call.
///
/// # Arguments
///
/// * `cb`: Callback where the passed argument is the current array index.
///
/// # Example
///
/// ```rust
/// #![feature(array_from_fn)]
///
/// let array = core::array::from_fn(|i| i);
/// assert_eq!(array, [0, 1, 2, 3, 4]);
/// ```
#[inline]
#[unstable(feature = "array_from_fn", issue = "89379")]
pub fn from_fn<F, T, const N: usize>(mut cb: F) -> [T; N]
where
F: FnMut(usize) -> T,
{
let mut idx = 0;
[(); N].map(|_| {
let res = cb(idx);
idx += 1;
res
})
}

/// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call.
/// Unlike `core::array::from_fn`, where the element creation can't fail, this version will return an error
/// if any element creation was unsuccessful.
///
/// # Arguments
///
/// * `cb`: Callback where the passed argument is the current array index.
///
/// # Example
///
/// ```rust
/// #![feature(array_from_fn)]
///
/// #[derive(Debug, PartialEq)]
/// enum SomeError {
/// Foo,
/// }
///
/// let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
/// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
///
/// let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
/// assert_eq!(another_array, Err(SomeError::Foo));
/// ```
#[inline]
#[unstable(feature = "array_from_fn", issue = "89379")]
pub fn try_from_fn<E, F, T, const N: usize>(cb: F) -> Result<[T; N], E>
where
F: FnMut(usize) -> Result<T, E>,
{
// SAFETY: we know for certain that this iterator will yield exactly `N`
// items.
unsafe { collect_into_array_rslt_unchecked(&mut (0..N).map(cb)) }
}

/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
#[stable(feature = "array_from_ref", since = "1.53.0")]
pub fn from_ref<T>(s: &T) -> &[T; 1] {
Expand Down Expand Up @@ -448,13 +511,15 @@ impl<T, const N: usize> [T; N] {
///
/// It is up to the caller to guarantee that `iter` yields at least `N` items.
/// Violating this condition causes undefined behavior.
unsafe fn collect_into_array_unchecked<I, const N: usize>(iter: &mut I) -> [I::Item; N]
unsafe fn collect_into_array_rslt_unchecked<E, I, T, const N: usize>(
iter: &mut I,
) -> Result<[T; N], E>
where
// Note: `TrustedLen` here is somewhat of an experiment. This is just an
// internal function, so feel free to remove if this bound turns out to be a
// bad idea. In that case, remember to also remove the lower bound
// `debug_assert!` below!
I: Iterator + TrustedLen,
I: Iterator<Item = Result<T, E>> + TrustedLen,
{
debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX));
debug_assert!(N <= iter.size_hint().0);
Expand All @@ -463,6 +528,21 @@ where
unsafe { collect_into_array(iter).unwrap_unchecked() }
}

// Infallible version of `collect_into_array_rslt_unchecked`.
unsafe fn collect_into_array_unchecked<I, const N: usize>(iter: &mut I) -> [I::Item; N]
where
I: Iterator + TrustedLen,
{
let mut map = iter.map(Ok::<_, Infallible>);

// SAFETY: The same safety considerations w.r.t. the iterator length
// apply for `collect_into_array_rslt_unchecked` as for
// `collect_into_array_unchecked`
match unsafe { collect_into_array_rslt_unchecked(&mut map) } {
Ok(array) => array,
}
}

/// Pulls `N` items from `iter` and returns them as an array. If the iterator
/// yields fewer than `N` items, `None` is returned and all already yielded
/// items are dropped.
Expand All @@ -473,43 +553,49 @@ where
///
/// If `iter.next()` panicks, all items already yielded by the iterator are
/// dropped.
fn collect_into_array<I, const N: usize>(iter: &mut I) -> Option<[I::Item; N]>
fn collect_into_array<E, I, T, const N: usize>(iter: &mut I) -> Option<Result<[T; N], E>>
where
I: Iterator,
I: Iterator<Item = Result<T, E>>,
{
if N == 0 {
// SAFETY: An empty array is always inhabited and has no validity invariants.
return unsafe { Some(mem::zeroed()) };
return unsafe { Some(Ok(mem::zeroed())) };
}

struct Guard<T, const N: usize> {
ptr: *mut T,
struct Guard<'a, T, const N: usize> {
array_mut: &'a mut [MaybeUninit<T>; N],
initialized: usize,
}

impl<T, const N: usize> Drop for Guard<T, N> {
impl<T, const N: usize> Drop for Guard<'_, T, N> {
fn drop(&mut self) {
debug_assert!(self.initialized <= N);

let initialized_part = crate::ptr::slice_from_raw_parts_mut(self.ptr, self.initialized);

// SAFETY: this raw slice will contain only initialized objects.
// SAFETY: this slice will contain only initialized objects.
unsafe {
crate::ptr::drop_in_place(initialized_part);
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
&mut self.array_mut.get_unchecked_mut(..self.initialized),
));
}
}
}

let mut array = MaybeUninit::uninit_array::<N>();
let mut guard: Guard<_, N> =
Guard { ptr: MaybeUninit::slice_as_mut_ptr(&mut array), initialized: 0 };
let mut guard = Guard { array_mut: &mut array, initialized: 0 };

while let Some(item_rslt) = iter.next() {
let item = match item_rslt {
Err(err) => {
return Some(Err(err));
}
Ok(elem) => elem,
};

while let Some(item) = iter.next() {
// SAFETY: `guard.initialized` starts at 0, is increased by one in the
// loop and the loop is aborted once it reaches N (which is
// `array.len()`).
unsafe {
array.get_unchecked_mut(guard.initialized).write(item);
guard.array_mut.get_unchecked_mut(guard.initialized).write(item);
}
guard.initialized += 1;

Expand All @@ -520,7 +606,7 @@ where
// SAFETY: the condition above asserts that all elements are
// initialized.
let out = unsafe { MaybeUninit::array_assume_init(array) };
return Some(out);
return Some(Ok(out));
}
}

Expand Down
Loading