From 78c802495a8b29d900f6a5166c0e5c829fb29ac3 Mon Sep 17 00:00:00 2001 From: Martin Ockajak Date: Sat, 13 Jul 2024 00:54:20 +0200 Subject: [PATCH] . --- README.md | 1 + src/extensions/collections/binary_heap.rs | 5 +++ src/extensions/collections/btree_map.rs | 5 +++ src/extensions/collections/btree_set.rs | 5 +++ src/extensions/collections/hash_map.rs | 5 +++ src/extensions/collections/hash_set.rs | 5 +++ src/extensions/collections/linked_list.rs | 5 +++ src/extensions/collections/slice.rs | 5 +++ src/extensions/collections/vec.rs | 5 +++ src/extensions/collections/vec_deque.rs | 5 +++ src/extensions/list.rs | 4 +-- src/extensions/map.rs | 39 +++++++++++++++++++++-- src/extensions/sequence.rs | 2 +- src/extensions/traversable.rs | 35 ++++++++++++++++++++ src/lib.rs | 1 + 15 files changed, 122 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6c398d0..473785a 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ data.group_by(|x| x % 2); // HashMap::from([(0, vec![2]), (1, vec![1, 3] | *flat* | :heavy_check_mark: | | :heavy_check_mark: | | | *fold* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | *fold_to* | :heavy_check_mark: | | :heavy_check_mark: | :heavy_check_mark: | +| *for_each* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | *frequencies* | :heavy_check_mark: | :heavy_check_mark: | | | | *frequencies_by* | :heavy_check_mark: | :heavy_check_mark: | | | | *group_by* | :heavy_check_mark: | | :heavy_check_mark: | | diff --git a/src/extensions/collections/binary_heap.rs b/src/extensions/collections/binary_heap.rs index 663039b..126e3fb 100644 --- a/src/extensions/collections/binary_heap.rs +++ b/src/extensions/collections/binary_heap.rs @@ -34,6 +34,11 @@ impl Traversable for BinaryHeap { self.iter().fold(initial_value, function) } + #[inline] + fn for_each(&self, function: impl FnMut(&Item)) { + self.iter().for_each(function) + } + #[inline] fn group_fold( &self, to_key: impl FnMut(&Item) -> K, initial_value: B, function: impl FnMut(B, &Item) -> B, diff --git a/src/extensions/collections/btree_map.rs b/src/extensions/collections/btree_map.rs index dbcbbe4..681e35a 100644 --- a/src/extensions/collections/btree_map.rs +++ b/src/extensions/collections/btree_map.rs @@ -132,4 +132,9 @@ impl Map for BTreeMap { { superset(self.keys(), elements) } + + #[inline] + fn for_each(&self, function: impl FnMut((&Key, &Value))) { + self.iter().for_each(function) + } } diff --git a/src/extensions/collections/btree_set.rs b/src/extensions/collections/btree_set.rs index f5bf6c2..2231386 100644 --- a/src/extensions/collections/btree_set.rs +++ b/src/extensions/collections/btree_set.rs @@ -34,6 +34,11 @@ impl Traversable for BTreeSet { self.iter().fold(initial_value, function) } + #[inline] + fn for_each(&self, function: impl FnMut(&Item)) { + self.iter().for_each(function) + } + #[inline] fn group_fold( &self, to_key: impl FnMut(&Item) -> K, initial_value: B, function: impl FnMut(B, &Item) -> B, diff --git a/src/extensions/collections/hash_map.rs b/src/extensions/collections/hash_map.rs index 6589553..535659e 100644 --- a/src/extensions/collections/hash_map.rs +++ b/src/extensions/collections/hash_map.rs @@ -61,6 +61,11 @@ impl Map for HashMap { self.iter().fold(initial_value, function) } + #[inline] + fn for_each(&self, function: impl FnMut((&Key, &Value))) { + self.iter().for_each(function) + } + #[inline] fn map(&self, function: impl FnMut((&Key, &Value)) -> (L, W)) -> Self::This where diff --git a/src/extensions/collections/hash_set.rs b/src/extensions/collections/hash_set.rs index 561be5d..8c392c1 100644 --- a/src/extensions/collections/hash_set.rs +++ b/src/extensions/collections/hash_set.rs @@ -35,6 +35,11 @@ impl Traversable for HashSet { self.iter().fold(initial_value, function) } + #[inline] + fn for_each(&self, function: impl FnMut(&Item)) { + self.iter().for_each(function) + } + #[inline] fn group_fold( &self, to_key: impl FnMut(&Item) -> K, initial_value: B, function: impl FnMut(B, &Item) -> B, diff --git a/src/extensions/collections/linked_list.rs b/src/extensions/collections/linked_list.rs index 7080b03..43993df 100644 --- a/src/extensions/collections/linked_list.rs +++ b/src/extensions/collections/linked_list.rs @@ -36,6 +36,11 @@ impl Traversable for LinkedList { self.iter().fold(initial_value, function) } + #[inline] + fn for_each(&self, function: impl FnMut(&Item)) { + self.iter().for_each(function) + } + #[inline] fn group_fold( &self, to_key: impl FnMut(&Item) -> K, initial_value: B, function: impl FnMut(B, &Item) -> B, diff --git a/src/extensions/collections/slice.rs b/src/extensions/collections/slice.rs index ba26743..6d8be6b 100644 --- a/src/extensions/collections/slice.rs +++ b/src/extensions/collections/slice.rs @@ -36,6 +36,11 @@ impl Traversable for [Item] { self.iter().fold(initial_value, function) } + #[inline] + fn for_each(&self, function: impl FnMut(&Item)) { + self.iter().for_each(function) + } + #[inline] fn group_fold( &self, to_key: impl FnMut(&Item) -> K, initial_value: B, function: impl FnMut(B, &Item) -> B, diff --git a/src/extensions/collections/vec.rs b/src/extensions/collections/vec.rs index c14211a..fdaf5f9 100644 --- a/src/extensions/collections/vec.rs +++ b/src/extensions/collections/vec.rs @@ -36,6 +36,11 @@ impl Traversable for Vec { self.iter().fold(initial_value, function) } + #[inline] + fn for_each(&self, function: impl FnMut(&Item)) { + self.iter().for_each(function) + } + #[inline] fn group_fold( &self, to_key: impl FnMut(&Item) -> K, initial_value: B, function: impl FnMut(B, &Item) -> B, diff --git a/src/extensions/collections/vec_deque.rs b/src/extensions/collections/vec_deque.rs index a8f03b2..71a109d 100644 --- a/src/extensions/collections/vec_deque.rs +++ b/src/extensions/collections/vec_deque.rs @@ -36,6 +36,11 @@ impl Traversable for VecDeque { self.iter().fold(initial_value, function) } + #[inline] + fn for_each(&self, function: impl FnMut(&Item)) { + self.iter().for_each(function) + } + #[inline] fn group_fold( &self, to_key: impl FnMut(&Item) -> K, initial_value: B, function: impl FnMut(B, &Item) -> B, diff --git a/src/extensions/list.rs b/src/extensions/list.rs index 4c33301..baa62f7 100644 --- a/src/extensions/list.rs +++ b/src/extensions/list.rs @@ -3,8 +3,8 @@ /// Methods have the following properties: /// /// - Requires the collection to represent a list -/// - May consume the collection and its elements -/// - May create a new collection +/// - May consume the list and its elements +/// - May create a new list /// pub trait List { /// Returns the first element of this sequence, or `None` if it is empty. diff --git a/src/extensions/map.rs b/src/extensions/map.rs index 77827bf..e0cbdb4 100644 --- a/src/extensions/map.rs +++ b/src/extensions/map.rs @@ -10,8 +10,8 @@ use std::iter::{Product, Sum}; /// Methods have the following properties: /// /// - Requires the collection to represent a map -/// - May consume the collection and its elements -/// - May create a new collection +/// - May consume the map and its entries +/// - May create a new map /// pub trait Map { type This; @@ -868,6 +868,41 @@ pub trait Map { { self.into_iter().fold(initial_value, function) } + + /// Calls a closure on each entry of this map. + /// + /// This is equivalent to using a [`for`] loop on the map, although + /// `break` and `continue` are not possible from a closure. It's generally + /// more idiomatic to use a `for` loop, but `for_each` may be more legible + /// when processing items at the end of longer map chains. + /// + /// [`for`]: ../../book/ch03-05-control-flow.html#looping-through-a-map-with-for + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use crate::cantrip::*; + /// use std::sync::mpsc::channel; + /// + /// let (tx, rx) = channel(); + /// (0..3).for_each(move |x| tx.send(x).unwrap()); + /// + /// let v: Vec<_> = rx.iter().collect(); + /// assert_eq!(v, vec![0, 1, 2]); + /// ``` + /// + /// For such a small example, a `for` loop may be cleaner, but `for_each` + /// might be preferable to keep a functional style with longer maps: + /// + /// ``` + /// (0..5).flat_map(|x| x * 100 .. x * 110) + /// .enumerate() + /// .filter(|&(i, x)| (i + x) % 3 == 0) + /// .for_each(|(i, x)| println!("{i}:{x}")); + /// ``` + fn for_each(&self, function: impl FnMut((&Key, &Value))); /// Creates a new map by retaining the values representing the intersection /// of the original map with another map i.e., the values that are diff --git a/src/extensions/sequence.rs b/src/extensions/sequence.rs index 362f1de..40f95ab 100644 --- a/src/extensions/sequence.rs +++ b/src/extensions/sequence.rs @@ -12,7 +12,7 @@ use std::ops::RangeBounds; /// Methods have the following properties: /// /// - Requires the collection to represent a sequence -/// - May consume the collection and its elements +/// - May consume the sequence and its elements /// - May create a new sequence /// pub trait Sequence { diff --git a/src/extensions/traversable.rs b/src/extensions/traversable.rs index 89ac429..f811662 100644 --- a/src/extensions/traversable.rs +++ b/src/extensions/traversable.rs @@ -237,6 +237,41 @@ pub trait Traversable { /// ``` fn fold(&self, initial_value: B, function: impl FnMut(B, &Item) -> B) -> B; + /// Calls a closure on each element of this collection. + /// + /// This is equivalent to using a [`for`] loop on the collection, although + /// `break` and `continue` are not possible from a closure. It's generally + /// more idiomatic to use a `for` loop, but `for_each` may be more legible + /// when processing items at the end of longer collection chains. + /// + /// [`for`]: ../../book/ch03-05-control-flow.html#looping-through-a-collection-with-for + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use crate::cantrip::*; + /// use std::sync::mpsc::channel; + /// + /// let (tx, rx) = channel(); + /// (0..3).for_each(move |x| tx.send(x).unwrap()); + /// + /// let v: Vec<_> = rx.iter().collect(); + /// assert_eq!(v, vec![0, 1, 2]); + /// ``` + /// + /// For such a small example, a `for` loop may be cleaner, but `for_each` + /// might be preferable to keep a functional style with longer collections: + /// + /// ``` + /// (0..5).flat_map(|x| x * 100 .. x * 110) + /// .enumerate() + /// .filter(|&(i, x)| (i + x) % 3 == 0) + /// .for_each(|(i, x)| println!("{i}:{x}")); + /// ``` + fn for_each(&self, function: impl FnMut(&Item)); + /// Creates `HashMap` of keys mapped and folded to values according to /// specified discriminator and folding operation functions. /// diff --git a/src/lib.rs b/src/lib.rs index 997562d..a44dda6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,6 +84,7 @@ /// | *flat* | :heavy_check_mark: | | :heavy_check_mark: | | /// | *fold* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | /// | *fold_to* | :heavy_check_mark: | | :heavy_check_mark: | :heavy_check_mark: | +/// | *for_each* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | /// | *frequencies* | :heavy_check_mark: | :heavy_check_mark: | | | /// | *frequencies_by* | :heavy_check_mark: | :heavy_check_mark: | | | /// | *group_by* | :heavy_check_mark: | | :heavy_check_mark: | |