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

add array::try_from_iter to improve discoverability and ergonomics #107979

Closed
wants to merge 3 commits into from
Closed
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
29 changes: 29 additions & 0 deletions library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -961,3 +961,32 @@ fn iter_next_chunk_erased<T>(
mem::forget(guard);
Ok(())
}

/// Tries to create an array `[T; N]` from the items of `iter`. If and only if `iter` holds
/// `>= N` items it returns `OK([T; N])`. Otherwise, `Err(IntoIter<T; N>)` is returned.
///
/// # Arguments
///
/// * `iter`: Type that implements `IntoIterator` where `Items = T`.
///
/// # Example
///
/// ```rust
/// #![feature(try_from_iter)]
/// let vec = vec![0, 1, 2, 3];
/// let array = core::array::try_from_iter::<_, 4>(vec);
/// assert!(array.is_ok());
/// assert_eq!(array.unwrap(), [0, 1, 2, 3]);
///
/// let vec = vec![0, 1, 2];
/// let array = core::array::try_from_iter::<_, 4>(vec);
/// assert!(array.is_err());
/// ```
#[unstable(feature = "try_from_iter", issue = "none")]
#[inline]
pub fn try_from_iter<I, const N: usize>(iter: I) -> Result<[I::Item; N], IntoIter<I::Item, N>>
Copy link
Member

Choose a reason for hiding this comment

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

This consumes iter, while next_chunk takes a &mut iter. Those are somewhat different semantics because it raises the question what happens when the remainder of the iterator could yield additional elements.

Copy link
Author

Choose a reason for hiding this comment

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

yess that is true! i was wondering about this as well when choosing the API layout, but ended up going with taking ownership of iter, as it seems to be the standard behavior of from functions and is probably what users would expect. Your point is still very valid, as most other collections that can be created through some form of from, From, try_from, or TryFrom don't have this size constraint that [T; N] has.

I'll add this to the RFC under Alterntives; yet, if this &mut self ends up making more sense then changing it to that should not be to difficult!

Copy link
Author

@emilHof emilHof Feb 13, 2023

Choose a reason for hiding this comment

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

One could also maybe imagine returning something like Result<([I::Item; N], I::Iterator), IntoIter<I::Item, N>> so that any remaining elements can be extracted from the original collection, but that might be a bit to contrived? It would mean you'd always have to expression match out of it, and would appear to severely reduce ergonomics.

where
I: IntoIterator,
{
iter.into_iter().next_chunk()
}
12 changes: 12 additions & 0 deletions library/core/tests/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,18 @@ fn array_into_iter_rfold() {
assert_eq!(s, 10432);
}

#[test]
fn array_try_fill_from() {
let vec = vec![0, 1, 2, 3];
let array = core::array::try_from_iter::<_, 4>(vec);
assert!(array.is_ok());
assert_eq!(array.unwrap(), [0, 1, 2, 3]);

let vec = vec![0, 1, 2];
let array = core::array::try_from_iter::<_, 4>(vec);
assert!(array.is_err());
}

#[cfg(not(panic = "abort"))]
#[test]
fn array_map_drops_unmapped_elements_on_panic() {
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
#![feature(utf8_chunks)]
#![feature(is_ascii_octdigit)]
#![feature(get_many_mut)]
#![feature(try_from_iter)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)]

Expand Down