collect_with/
collect.rs

1use crate::{ExtendWithCapacity, common::collect_iterator};
2
3// Implement CollectWithCapacity trait for Iterator
4impl<I: Iterator> CollectWithCapacity for I {}
5/// Trait for collecting iterator elements into a collection with specified
6/// capacity
7pub trait CollectWithCapacity: Iterator {
8  /// Collect iterator elements into a collection with pre-allocated capacity.
9  ///
10  /// - `capacity`
11  ///   - Initial capacity to allocate for the collection
12  /// - `T`
13  ///   - Collection type that implements ExtendWithCapacity (e.g., `Vec<X>`,
14  ///     String, `HashMap<K, V>`)
15  ///
16  /// > See also: [collect_with()](crate::CollectWith::collect_with)
17  fn collect_with_capacity<T>(self, capacity: usize) -> T
18  where
19    T: ExtendWithCapacity<Self::Item>,
20    Self: Sized,
21  {
22    collect_iterator(self, false, |_| capacity)
23  }
24}
25/// Implement CollectWith trait for Iterator
26impl<I: Iterator> CollectWith for I {}
27
28/// Trait for collecting iterator elements with flexible capacity calculation
29pub trait CollectWith: Iterator {
30  /// Collect elements using a capacity calculated from a closure
31  ///
32  /// - `capacity`
33  ///   - Closure that calculates capacity based on iterator size hints
34  ///
35  /// ## About the Final Capacity Size
36  ///
37  /// For example, `(0..10).collect_with::<Vec<_>>(|_size_bound| 2)`
38  ///
39  /// 1. `(0..10).size_hint()` returns `(10, Some(10))`.
40  /// 2. _size_bound is 10.
41  /// 3. The closure returns 2, the final capacity is `max(10, 2)` = 10.
42  /// 4. The vector is created with Vec::with_capacity(10).
43  ///
44  /// ## Example
45  ///
46  /// ```
47  /// use collect_with::CollectWith;
48  ///
49  /// let s = [vec!["a"], vec!["b", "c", "d"]]
50  ///   .into_iter()
51  ///   .flatten()
52  ///   .collect_with::<String>(|size| match size {
53  ///     0 => 8,
54  ///     n => n,
55  ///   });
56  /// assert_eq!(s.len(), 4);
57  /// assert_eq!(s.capacity(), 8);
58  /// ```
59  ///
60  /// The collection may allocate more capacity than calculated if needed.
61  /// If you need an exact capacity size, please use
62  /// [collect_with_exact()](crate::CollectWith::collect_with_exact)
63  fn collect_with<T>(self, capacity: impl FnOnce(usize) -> usize) -> T
64  where
65    T: ExtendWithCapacity<Self::Item>,
66    Self: Sized,
67  {
68    collect_iterator(self, false, capacity)
69  }
70
71  /// Collect elements using exact capacity calculated from a closure.
72  ///
73  /// - `capacity`
74  ///   - Closure that calculates exact capacity requirement
75  ///
76  /// The collection will strictly use the calculated capacity without
77  /// overallocation.
78  fn collect_with_exact<T>(self, capacity: impl FnOnce(usize) -> usize) -> T
79  where
80    T: ExtendWithCapacity<Self::Item>,
81    Self: Sized,
82  {
83    collect_iterator(self, true, capacity)
84  }
85}
86
87#[cfg(test)]
88mod tests {
89  use alloc::{string::String, vec};
90
91  use super::*;
92
93  #[ignore]
94  #[test]
95  fn test_collect_with() {
96    let s = [vec!["a"], vec!["b", "c", "d"]]
97      .into_iter()
98      .flatten()
99      .collect_with::<String>(|size| match size {
100        0 => 8,
101        n => n,
102      });
103    assert_eq!(s.len(), 4);
104    assert_eq!(s.capacity(), 8);
105  }
106}