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}