From 2db05230d35c068c557fe476cf16197836580c2d Mon Sep 17 00:00:00 2001 From: bstrie <865233+bstrie@users.noreply.github.com> Date: Sun, 11 Apr 2021 18:38:44 -0400 Subject: [PATCH] impl From<[(K, V); N]> for std::collections --- library/alloc/src/collections/binary_heap.rs | 24 +++++++ library/alloc/src/collections/btree/map.rs | 29 +++++++- .../alloc/src/collections/btree/map/tests.rs | 7 ++ library/alloc/src/collections/btree/set.rs | 22 ++++++ .../alloc/src/collections/btree/set/tests.rs | 7 ++ library/alloc/src/collections/linked_list.rs | 21 ++++++ .../alloc/src/collections/vec_deque/mod.rs | 22 ++++++ library/alloc/src/vec/mod.rs | 9 +-- library/std/src/collections/hash/map.rs | 68 ++++++++++++++----- library/std/src/collections/hash/map/tests.rs | 12 ++++ library/std/src/collections/hash/set.rs | 37 ++++++++-- library/std/src/collections/hash/set/tests.rs | 12 ++++ 12 files changed, 244 insertions(+), 26 deletions(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index bf9f7432fb536..2f999a10a9610 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -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 From> for BinaryHeap { } } +#[stable(feature = "std_collections_from_array", since = "1.55.0")] +impl From<[T; N]> for BinaryHeap { + /// ``` + /// 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 From> for Vec { /// Converts a `BinaryHeap` into a `Vec`. diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index a0dbb289252f6..708389579dbcf 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -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.55.0")] +impl From<[(K, V); N]> for BTreeMap { + /// ``` + /// 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 BTreeMap { /// Gets an iterator over the entries of the map, sorted by key. /// diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 3a74b6a6fa85c..1e61692b7c63c 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -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); +} diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index a331b8d8e4bbb..56c2cb56b5ba5 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -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 FromIterator for BTreeSet { } } +#[stable(feature = "std_collections_from_array", since = "1.55.0")] +impl From<[T; N]> for BTreeSet { + /// ``` + /// 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 IntoIterator for BTreeSet { type Item = T; diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 4cb6e3d6619dc..de7a10dca7b8c 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -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); +} diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index a5481fd175e30..8b978a4e806e7 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -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 Hash for LinkedList { } } +#[stable(feature = "std_collections_from_array", since = "1.55.0")] +impl From<[T; N]> for LinkedList { + /// ``` + /// 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() { diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index d3e70991ad518..98514b43e7f52 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -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 From> for Vec { } } } + +#[stable(feature = "std_collections_from_array", since = "1.55.0")] +impl From<[T; N]> for VecDeque { + /// ``` + /// 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() + } +} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 91c3b16deee77..617c76a680b9f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -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` with a given value. diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 3dcc5cd2b5911..fdc64850f714f 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -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.55.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 From<[(K, V); N]> for HashMap +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 diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 819be14222752..def085e380b19 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -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)]); +} diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 8c801b9f1285d..6e58ebdce507d 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -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.55.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 From<[T; N]> for HashSet +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 Extend for HashSet where diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs index 40f8467fd93fd..6a625e6243c21 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -484,3 +484,15 @@ fn test_drain_filter_pred_panic_leak() { assert_eq!(DROPS.load(Ordering::SeqCst), 3); assert_eq!(set.len(), 0); } + +#[test] +fn from_array() { + let set = HashSet::from([1, 2, 3, 4]); + let unordered_duplicates = HashSet::from([4, 1, 4, 3, 2]); + assert_eq!(set, 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 = HashSet::from([1, 2]); +}