Skip to content

Stabilize impl From<[(K, V); N]> for HashMap (and friends) #84111

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

Merged
merged 2 commits into from
Jul 25, 2021
Merged
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
24 changes: 24 additions & 0 deletions library/alloc/src/collections/binary_heap.rs
Original file line number Diff line number Diff line change
@@ -209,6 +209,14 @@ use super::SpecExtend;
/// assert!(heap.is_empty())
/// ```
///
/// A `BinaryHeap` with a known list of items can be initialized from an array:
///
/// ```
/// use std::collections::BinaryHeap;
///
/// let heap = BinaryHeap::from([1, 5, 2]);
/// ```
///
/// ## Min-heap
///
/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to
@@ -1443,6 +1451,22 @@ impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
}
}

#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<T: Ord, const N: usize> From<[T; N]> for BinaryHeap<T> {
/// ```
/// use std::collections::BinaryHeap;
///
/// let mut h1 = BinaryHeap::from([1, 4, 2, 3]);
/// let mut h2: BinaryHeap<_> = [1, 4, 2, 3].into();
/// while let Some((a, b)) = h1.pop().zip(h2.pop()) {
/// assert_eq!(a, b);
/// }
/// ```
fn from(arr: [T; N]) -> Self {
core::array::IntoIter::new(arr).collect()
}
}

#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T> From<BinaryHeap<T>> for Vec<T> {
/// Converts a `BinaryHeap<T>` into a `Vec<T>`.
29 changes: 28 additions & 1 deletion library/alloc/src/collections/btree/map.rs
Original file line number Diff line number Diff line change
@@ -109,7 +109,20 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
/// }
/// ```
///
/// `BTreeMap` also implements an [`Entry API`], which allows for more complex
/// A `BTreeMap` with a known list of items can be initialized from an array:
///
/// ```
/// use std::collections::BTreeMap;
///
/// let solar_distance = BTreeMap::from([
/// ("Mercury", 0.4),
/// ("Venus", 0.7),
/// ("Earth", 1.0),
/// ("Mars", 1.5),
/// ]);
/// ```
///
/// `BTreeMap` implements an [`Entry API`], which allows for complex
/// methods of getting, setting, updating and removing keys and their values:
///
/// [`Entry API`]: BTreeMap::entry
@@ -2030,6 +2043,20 @@ where
}
}

#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<K: Ord, V, const N: usize> From<[(K, V); N]> for BTreeMap<K, V> {
/// ```
/// use std::collections::BTreeMap;
///
/// let map1 = BTreeMap::from([(1, 2), (3, 4)]);
/// let map2: BTreeMap<_, _> = [(1, 2), (3, 4)].into();
/// assert_eq!(map1, map2);
/// ```
fn from(arr: [(K, V); N]) -> Self {
core::array::IntoIter::new(arr).collect()
}
}

impl<K, V> BTreeMap<K, V> {
/// Gets an iterator over the entries of the map, sorted by key.
///
7 changes: 7 additions & 0 deletions library/alloc/src/collections/btree/map/tests.rs
Original file line number Diff line number Diff line change
@@ -2173,3 +2173,10 @@ fn test_insert_remove_intertwined_ord_chaos() {
}
map.check_invariants();
}

#[test]
fn from_array() {
let map = BTreeMap::from([(1, 2), (3, 4)]);
let unordered_duplicates = BTreeMap::from([(3, 4), (1, 2), (1, 2)]);
assert_eq!(map, unordered_duplicates);
}
22 changes: 22 additions & 0 deletions library/alloc/src/collections/btree/set.rs
Original file line number Diff line number Diff line change
@@ -59,6 +59,14 @@ use super::Recover;
/// println!("{}", book);
/// }
/// ```
///
/// A `BTreeSet` with a known list of items can be initialized from an array:
///
/// ```
/// use std::collections::BTreeSet;
///
/// let set = BTreeSet::from([1, 2, 3]);
/// ```
#[derive(Hash, PartialEq, Eq, Ord, PartialOrd)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "BTreeSet")]
@@ -1057,6 +1065,20 @@ impl<T: Ord> FromIterator<T> for BTreeSet<T> {
}
}

#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
/// let set1 = BTreeSet::from([1, 2, 3, 4]);
/// let set2: BTreeSet<_> = [1, 2, 3, 4].into();
/// assert_eq!(set1, set2);
/// ```
fn from(arr: [T; N]) -> Self {
core::array::IntoIter::new(arr).collect()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> IntoIterator for BTreeSet<T> {
type Item = T;
7 changes: 7 additions & 0 deletions library/alloc/src/collections/btree/set/tests.rs
Original file line number Diff line number Diff line change
@@ -738,3 +738,10 @@ fn test_split_off_large_random_sorted() {
assert!(set.into_iter().eq(data.clone().into_iter().filter(|x| *x < key)));
assert!(right.into_iter().eq(data.into_iter().filter(|x| *x >= key)));
}

#[test]
fn from_array() {
let set = BTreeSet::from([1, 2, 3, 4]);
let unordered_duplicates = BTreeSet::from([4, 1, 4, 3, 2]);
assert_eq!(set, unordered_duplicates);
}
21 changes: 21 additions & 0 deletions library/alloc/src/collections/linked_list.rs
Original file line number Diff line number Diff line change
@@ -31,6 +31,13 @@ mod tests;
/// The `LinkedList` allows pushing and popping elements at either end
/// in constant time.
///
/// A `LinkedList` with a known list of items can be initialized from an array:
/// ```
/// use std::collections::LinkedList;
///
/// let list = LinkedList::from([1, 2, 3]);
/// ```
///
/// NOTE: It is almost always better to use `Vec` or `VecDeque` because
/// array-based containers are generally faster,
/// more memory efficient, and make better use of CPU cache.
@@ -1767,6 +1774,20 @@ impl<T: Hash> Hash for LinkedList<T> {
}
}

#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<T, const N: usize> From<[T; N]> for LinkedList<T> {
/// ```
/// use std::collections::LinkedList;
///
/// let list1 = LinkedList::from([1, 2, 3, 4]);
/// let list2: LinkedList<_> = [1, 2, 3, 4].into();
/// assert_eq!(list1, list2);
/// ```
fn from(arr: [T; N]) -> Self {
core::array::IntoIter::new(arr).collect()
}
}

// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters.
#[allow(dead_code)]
fn assert_covariance() {
22 changes: 22 additions & 0 deletions library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
@@ -67,6 +67,14 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible
/// push onto the back in this manner, and iterating over `VecDeque` goes front
/// to back.
///
/// A `VecDeque` with a known list of items can be initialized from an array:
///
/// ```
/// use std::collections::VecDeque;
///
/// let deq = VecDeque::from([-1, 0, 1]);
/// ```
///
/// Since `VecDeque` is a ring buffer, its elements are not necessarily contiguous
/// in memory. If you want to access the elements as a single slice, such as for
/// efficient sorting, you can use [`make_contiguous`]. It rotates the `VecDeque`
@@ -2855,3 +2863,17 @@ impl<T> From<VecDeque<T>> for Vec<T> {
}
}
}

#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<T, const N: usize> From<[T; N]> for VecDeque<T> {
/// ```
/// use std::collections::VecDeque;
///
/// let deq1 = VecDeque::from([1, 2, 3, 4]);
/// let deq2: VecDeque<_> = [1, 2, 3, 4].into();
/// assert_eq!(deq1, deq2);
/// ```
fn from(arr: [T; N]) -> Self {
core::array::IntoIter::new(arr).collect()
}
}
9 changes: 5 additions & 4 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
@@ -152,12 +152,13 @@ mod spec_extend;
/// assert_eq!(vec, [7, 1, 2, 3]);
/// ```
///
/// The [`vec!`] macro is provided to make initialization more convenient:
/// The [`vec!`] macro is provided for convenient initialization:
///
/// ```
/// let mut vec = vec![1, 2, 3];
/// vec.push(4);
/// assert_eq!(vec, [1, 2, 3, 4]);
/// let mut vec1 = vec![1, 2, 3];
/// vec1.push(4);
/// let vec2 = Vec::from([1, 2, 3, 4]);
/// assert_eq!(vec1, vec2);
/// ```
///
/// It can also initialize each element of a `Vec<T>` with a given value.
68 changes: 51 additions & 17 deletions library/std/src/collections/hash/map.rs
Original file line number Diff line number Diff line change
@@ -124,8 +124,21 @@ use crate::sys;
/// }
/// ```
///
/// `HashMap` also implements an [`Entry API`](#method.entry), which allows
/// for more complex methods of getting, setting, updating and removing keys and
/// A `HashMap` with a known list of items can be initialized from an array:
///
/// ```
/// use std::collections::HashMap;
///
/// let solar_distance = HashMap::from([
/// ("Mercury", 0.4),
/// ("Venus", 0.7),
/// ("Earth", 1.0),
/// ("Mars", 1.5),
/// ]);
/// ```
///
/// `HashMap` implements an [`Entry API`](#method.entry), which allows
/// for complex methods of getting, setting, updating and removing keys and
/// their values:
///
/// ```
@@ -179,27 +192,17 @@ use crate::sys;
/// }
///
/// // Use a HashMap to store the vikings' health points.
/// let mut vikings = HashMap::new();
///
/// vikings.insert(Viking::new("Einar", "Norway"), 25);
/// vikings.insert(Viking::new("Olaf", "Denmark"), 24);
/// vikings.insert(Viking::new("Harald", "Iceland"), 12);
/// let vikings = HashMap::from([
/// (Viking::new("Einar", "Norway"), 25),
/// (Viking::new("Olaf", "Denmark"), 24),
/// (Viking::new("Harald", "Iceland"), 12),
/// ]);
///
/// // Use derived implementation to print the status of the vikings.
/// for (viking, health) in &vikings {
/// println!("{:?} has {} hp", viking, health);
/// }
/// ```
///
/// A `HashMap` with fixed list of elements can be initialized from an array:
///
/// ```
/// use std::collections::HashMap;
///
/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)]
/// .iter().cloned().collect();
/// // use the values stored in map
/// ```

#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1151,6 +1154,37 @@ where
}
}

#[stable(feature = "std_collections_from_array", since = "1.56.0")]
// Note: as what is currently the most convenient built-in way to construct
// a HashMap, a simple usage of this function must not *require* the user
// to provide a type annotation in order to infer the third type parameter
// (the hasher parameter, conventionally "S").
// To that end, this impl is defined using RandomState as the concrete
// type of S, rather than being generic over `S: BuildHasher + Default`.
// It is expected that users who want to specify a hasher will manually use
// `with_capacity_and_hasher`.
// If type parameter defaults worked on impls, and if type parameter
// defaults could be mixed with const generics, then perhaps
// this could be generalized.
// See also the equivalent impl on HashSet.
impl<K, V, const N: usize> From<[(K, V); N]> for HashMap<K, V, RandomState>
where
K: Eq + Hash,
{
/// # Examples
///
/// ```
/// use std::collections::HashMap;
///
/// let map1 = HashMap::from([(1, 2), (3, 4)]);
/// let map2: HashMap<_, _> = [(1, 2), (3, 4)].into();
/// assert_eq!(map1, map2);
/// ```
fn from(arr: [(K, V); N]) -> Self {
crate::array::IntoIter::new(arr).collect()
}
}

/// An iterator over the entries of a `HashMap`.
///
/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its
12 changes: 12 additions & 0 deletions library/std/src/collections/hash/map/tests.rs
Original file line number Diff line number Diff line change
@@ -1085,3 +1085,15 @@ mod test_drain_filter {
assert_eq!(map.len(), 2);
}
}

#[test]
fn from_array() {
let map = HashMap::from([(1, 2), (3, 4)]);
let unordered_duplicates = HashMap::from([(3, 4), (1, 2), (1, 2)]);
assert_eq!(map, unordered_duplicates);

// This next line must infer the hasher type parameter.
// If you make a change that causes this line to no longer infer,
// that's a problem!
let _must_not_require_type_annotation = HashMap::from([(1, 2)]);
}
37 changes: 33 additions & 4 deletions library/std/src/collections/hash/set.rs
Original file line number Diff line number Diff line change
@@ -95,14 +95,12 @@ use super::map::{map_try_reserve_error, RandomState};
/// }
/// ```
///
/// A `HashSet` with fixed list of elements can be initialized from an array:
/// A `HashSet` with a known list of items can be initialized from an array:
///
/// ```
/// use std::collections::HashSet;
///
/// let viking_names: HashSet<&'static str> =
/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect();
/// // use the values stored in the set
/// let viking_names = HashSet::from(["Einar", "Olaf", "Harald"]);
/// ```
///
/// [hash set]: crate::collections#use-the-set-variant-of-any-of-these-maps-when
@@ -998,6 +996,37 @@ where
}
}

#[stable(feature = "std_collections_from_array", since = "1.56.0")]
// Note: as what is currently the most convenient built-in way to construct
// a HashSet, a simple usage of this function must not *require* the user
// to provide a type annotation in order to infer the third type parameter
// (the hasher parameter, conventionally "S").
// To that end, this impl is defined using RandomState as the concrete
// type of S, rather than being generic over `S: BuildHasher + Default`.
// It is expected that users who want to specify a hasher will manually use
// `with_capacity_and_hasher`.
// If type parameter defaults worked on impls, and if type parameter
// defaults could be mixed with const generics, then perhaps
// this could be generalized.
// See also the equivalent impl on HashMap.
impl<T, const N: usize> From<[T; N]> for HashSet<T, RandomState>
where
T: Eq + Hash,
{
/// # Examples
///
/// ```
/// use std::collections::HashSet;
///
/// let set1 = HashSet::from([1, 2, 3, 4]);
/// let set2: HashSet<_> = [1, 2, 3, 4].into();
/// assert_eq!(set1, set2);
/// ```
fn from(arr: [T; N]) -> Self {
crate::array::IntoIter::new(arr).collect()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> Extend<T> for HashSet<T, S>
where
Loading