collect_with/
try_collect.rs

1use alloc::vec::Vec;
2
3use crate::{ExtendWithCapacity, TryExtract, common::get_max_hint_bound};
4
5impl<I: Iterator> TryCollectWith for I {}
6
7pub trait TryCollectWith: Iterator {
8  /// Attempt to collect iterator elements into a collection with error handling
9  ///
10  /// ## Closure
11  ///
12  /// * `capacity` - Closure that calculates initial capacity based on iterator
13  ///   size hint
14  ///
15  /// ## Type Parameters
16  ///
17  /// * `T` - Target collection type implementing ExtendWithCapacity
18  /// * `OK` - Type of successfully extracted values
19  /// * `ERR` - Error type returned from failed extraction
20  ///
21  /// ## Behavior
22  ///
23  /// - Uses size hints to pre-allocate capacity
24  /// - Short-circuits on first extraction error
25  /// - Returns collected values or first encountered error
26  ///
27  /// ## Example
28  ///
29  /// ```rust
30  /// use collect_with::TryCollectWith;
31  ///
32  /// let result = ["42", "76", "abc"]
33  ///   .into_iter()
34  ///   .map(|x| x.parse::<i32>()) // &str -> Result<i32>
35  ///   .try_collect_with::<Vec<_>, _, _>(|u| u + 3); // -> Result<Vec<i32>, ParseIntError>
36  ///
37  /// assert!(result.is_err());
38  /// ```
39  fn try_collect_with<'a, T, OK, ERR>(
40    self,
41    capacity: impl FnOnce(usize) -> usize,
42  ) -> Result<T, ERR>
43  where
44    T: ExtendWithCapacity<OK>,
45    Self: Sized,
46    Self::Item: TryExtract<'a, Ok = OK, Err = ERR>,
47  {
48    let bound = get_max_hint_bound(self.size_hint());
49    let mut container = T::with_capacity(capacity(bound).max(bound));
50
51    for item in self {
52      let value = item.try_extract()?;
53      container.extend(core::iter::once(value));
54    }
55
56    Ok(container)
57  }
58
59  /// Convenience method for collecting into `Result<Vec<OK>, Err>`
60  ///
61  /// ## Closure
62  ///
63  /// - `capacity`
64  ///   - Closure that calculates initial vector capacity
65  ///
66  /// ## Example
67  ///
68  /// ```rust
69  /// use collect_with::TryCollectWith;
70  ///
71  /// let result = ["42", "73"]
72  ///   .into_iter()
73  ///   .map(|x| x.parse::<i32>()) // &str -> Result<i32>
74  ///   .try_collect_vec_with(|u| u+2); // -> Result<Vec<i32>, ParseIntError>
75  ///
76  /// assert_eq!(result.as_deref(), Ok(&[42, 73][..]));
77  /// ```
78  #[cfg(feature = "collect_vec")]
79  fn try_collect_vec_with<'a, OK, ERR>(
80    self,
81    capacity: impl FnOnce(usize) -> usize,
82  ) -> Result<Vec<OK>, ERR>
83  where
84    Self: Sized,
85    Self::Item: TryExtract<'a, Ok = OK, Err = ERR>,
86  {
87    self.try_collect_with(capacity)
88  }
89}