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

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

Merged
merged 2 commits into from
Jul 25, 2021
Merged
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
24 changes: 24 additions & 0 deletions library/alloc/src/collections/binary_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>`.
Expand Down
29 changes: 28 additions & 1 deletion library/alloc/src/collections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
bstrie marked this conversation as resolved.
Show resolved Hide resolved
/// methods of getting, setting, updating and removing keys and their values:
///
/// [`Entry API`]: BTreeMap::entry
Expand Down Expand Up @@ -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.
///
Expand Down
7 changes: 7 additions & 0 deletions library/alloc/src/collections/btree/map/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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")]
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions library/alloc/src/collections/btree/set/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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.
Expand Down Expand Up @@ -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() {
Expand Down
22 changes: 22 additions & 0 deletions library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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
Expand Up @@ -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:
bstrie marked this conversation as resolved.
Show resolved Hide resolved
///
/// ```
/// 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);
bstrie marked this conversation as resolved.
Show resolved Hide resolved
/// ```
///
/// It can also initialize each element of a `Vec<T>` with a given value.
Expand Down
68 changes: 51 additions & 17 deletions library/std/src/collections/hash/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
///
/// ```
Expand Down Expand Up @@ -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")]
Expand Down Expand Up @@ -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
///
/// ```
bstrie marked this conversation as resolved.
Show resolved Hide resolved
/// 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
Expand Down
12 changes: 12 additions & 0 deletions library/std/src/collections/hash/map/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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
Expand Down Expand Up @@ -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
///
/// ```
bstrie marked this conversation as resolved.
Show resolved Hide resolved
/// 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
Expand Down
Loading