better_collect/traits/
ref_collector.rs

1use std::ops::ControlFlow;
2
3use crate::{Collector, Combine, Funnel, IntoCollector, assert_collector, assert_ref_collector};
4
5/// A [`Collector`] that can also collect items by mutable reference.
6///
7/// This trait introduces one additional method, [`collect_ref`](RefCollector::collect_ref),
8/// which takes a mutable reference to an item.
9///
10/// It exists primarily to support [`combine()`].
11/// Since [`Collector`] consumes items by ownership, each item cannot normally be passed further.
12/// A type implementing this trait essentially declares: “A view of an item is enough for me
13/// to collect it. Feel free to keep using it elsewhere.”
14/// This enables items to flow through multiple collectors while maintaining composability.
15/// See [`combine()`] for a deeper explanation.
16///
17/// # Difference from [`Collector<Item = &mut T>`]
18///
19/// Although both can collect mutable references, [`Collector<Item = &mut T>`]
20/// implies ownership of those references and their lifetimes.
21/// As such, it cannot be safely fed with references to items that will later be consumed.
22///
23/// For example, imagine a `Vec<&mut T>` collector:
24/// it would hold the references beyond a single iteration,
25/// preventing the item from being passed to another collector.
26/// [`RefCollector`], in contrast, borrows mutably just long enough to collect,
27/// then immediately releases the borrow, enabling true chaining.
28///
29/// # Dyn Compatibility
30///
31/// This trait is *dyn-compatible*, meaning it can be used as a trait object.
32/// You do not need to specify the [`Output`](crate::Collector::Output) type;
33/// providing the [`Item`] type is enough.
34///
35/// For example:
36///
37/// ```no_run
38/// # use better_collect::prelude::*;
39/// # fn foo(_:
40/// &mut dyn RefCollector<Item = i32>
41/// # ) {}
42/// ```
43///
44/// With the same [`Item`] type, a `dyn RefCollector` can be upcast to
45/// a `dyn Collector`.
46///
47/// ```no_run
48/// use better_collect::prelude::*;
49///
50/// let ref_collector: &mut dyn RefCollector<Item = i32> = &mut vec![].into_collector();
51/// let collector: &mut dyn Collector<Item = i32> = ref_collector; // upcast
52/// ```
53///
54/// [`combine()`]: RefCollector::combine
55/// [`Item`]: crate::Collector::Item
56pub trait RefCollector: Collector {
57    /// Collects an item and returns a [`ControlFlow`] indicating whether
58    /// the collector has stopped accumulating right after this operation.
59    ///
60    /// See [`Collector::collect()`] for requirements regarding the returned [`ControlFlow`].
61    ///
62    /// After implementing this method, [`Collector::collect()`] can generally be forwarded
63    /// like this:
64    ///
65    /// ```no_run
66    /// # use better_collect::prelude::*;
67    /// # use std::ops::ControlFlow;
68    /// # struct Foo;
69    /// # impl Collector for Foo {
70    /// # type Item = ();
71    /// # type Output = ();
72    /// fn collect(&mut self, mut item: Self::Item) -> ControlFlow<()> {
73    ///     self.collect_ref(&mut item)
74    /// }
75    /// #     fn finish(self) -> Self::Output {}
76    /// # }
77    /// # impl RefCollector for Foo {
78    /// #     fn collect_ref(&mut self, item: &mut Self::Item) -> ControlFlow<()> {
79    /// #         ControlFlow::Continue(())
80    /// #     }
81    /// # }
82    /// ```
83    fn collect_ref(&mut self, item: &mut Self::Item) -> ControlFlow<()>;
84
85    /// Use [`combine()`](RefCollector::combine).
86    #[inline]
87    #[deprecated(since = "0.3.0", note = "Use `combine()`")]
88    fn then<C>(self, other: C) -> Combine<Self, C::IntoCollector>
89    where
90        Self: Sized,
91        C: IntoCollector<Item = Self::Item>,
92    {
93        self.combine(other)
94    }
95
96    /// The most important adaptor. The reason why this crate exists.
97    ///
98    /// Creates a [`Collector`] that lets both collectors collect the same item.
99    /// For each item collected, the first collector collects the item by mutable reference,
100    /// then the second one collects it by either mutable reference or ownership.
101    /// Together, they form a pipeline where each collector processes the item in turn,
102    /// and the final one consumes by ownership.
103    ///
104    /// If the second collector implements [`RefCollector`], this adaptor implements [`RefCollector`],
105    /// allowing the chain to be extended further with additional `combine()` calls.
106    /// Otherwise, it becomes the endpoint of the pipeline.
107    ///
108    /// # Examples
109    ///
110    /// ```
111    /// use better_collect::{prelude::*, cmp::Max};
112    ///
113    /// let mut collector = vec![].into_collector().combine(Max::new());
114    ///
115    /// assert!(collector.collect(4).is_continue());
116    /// assert!(collector.collect(2).is_continue());
117    /// assert!(collector.collect(6).is_continue());
118    /// assert!(collector.collect(3).is_continue());
119    ///
120    /// assert_eq!(collector.finish(), (vec![4, 2, 6, 3], Some(6)));
121    /// ```
122    ///
123    /// Even if one collector stops, `combine()` continues as the other does.
124    /// It only stops when both collectors stop.
125    ///
126    /// ```
127    /// use better_collect::prelude::*;
128    ///
129    /// let mut collector = vec![].into_collector().take(3).combine(()); // `()` always stops collecting.
130    ///
131    /// assert!(collector.collect(()).is_continue());
132    /// assert!(collector.collect(()).is_continue());
133    /// // Since `.take(3)` only takes 3 items,
134    /// // it hints a stop right after the 3rd item is collected.
135    /// assert!(collector.collect(()).is_break());
136    /// # // Internal assertion.
137    /// # assert!(collector.collect(()).is_break());
138    ///
139    /// assert_eq!(collector.finish(), (vec![(); 3], ()));
140    /// ```
141    ///
142    /// Collectors can be chained with `combine()` as many as you want,
143    /// as long as every of them except the last implements [`RefCollector`].
144    ///
145    /// Here’s the solution to [LeetCode #1491] to demonstrate it:
146    ///
147    /// ```
148    /// use better_collect::{
149    ///     prelude::*,
150    ///     cmp::{Min, Max}, num::Sum, Count,
151    /// };
152    ///
153    /// # struct Solution;
154    /// impl Solution {
155    ///     pub fn average(salary: Vec<i32>) -> f64 {
156    ///         let (((min, max), count), sum) = salary
157    ///             .into_iter()
158    ///             .better_collect(
159    ///                 Min::new()
160    ///                     .copying()
161    ///                     .combine(Max::new().copying())
162    ///                     .combine(Count::new())
163    ///                     .combine(Sum::<i32>::new())
164    ///             );
165    ///                 
166    ///         let (min, max) = (min.unwrap(), max.unwrap());
167    ///         (sum - max - min) as f64 / (count - 2) as f64
168    ///     }
169    /// }
170    ///
171    /// fn correct(actual: f64, expected: f64) -> bool {
172    ///     const DELTA: f64 = 1E-5;
173    ///     (actual - expected).abs() <= DELTA
174    /// }
175    ///
176    /// assert!(correct(
177    ///     Solution::average(vec![5, 3, 1, 2]), 2.5
178    /// ));
179    /// assert!(correct(
180    ///     Solution::average(vec![1, 2, 4]), 2.0
181    /// ));
182    /// ```
183    ///
184    /// [LeetCode #1491]: https://leetcode.com/problems/average-salary-excluding-the-minimum-and-maximum-salary
185    #[inline]
186    fn combine<C>(self, other: C) -> Combine<Self, C::IntoCollector>
187    where
188        Self: Sized,
189        C: IntoCollector<Item = Self::Item>,
190    {
191        assert_collector(Combine::new(self, other.into_collector()))
192    }
193
194    /// Creates a [`RefCollector`] that maps a mutable reference to an item
195    /// into another mutable reference.
196    ///
197    /// This is used when a [`combine`] chain expects to collect `T`,
198    /// but you have a collector that collects `U`. In that case,
199    /// you can use `funnel()` to transform `U` into `T` before passing it along.
200    ///
201    /// Unlike [`Collector::map()`] or [`Collector::map_ref()`], this adaptor works
202    /// seamlessly with [`RefCollector`]s by forwarding items directly through
203    /// the [`collect_ref`] method.
204    /// This avoids cloning because the underlying collector does not need owndership of items.
205    ///
206    /// # Examples
207    ///
208    /// ```
209    /// use better_collect::prelude::*;
210    ///
211    /// let vecs = [
212    ///     vec!["a".to_owned(), "b".to_owned(), "c".to_owned()],
213    ///     vec!["1".to_owned(), "2".to_owned(), "3".to_owned()],
214    ///     vec!["swordswoman".to_owned(), "singer".to_owned()],
215    /// ];
216    ///
217    /// let (concat_firsts, _lens) = vecs
218    ///     .into_iter()
219    ///     .better_collect(
220    ///         ConcatString::new()
221    ///             // We only need a reference to a string to concatenate.
222    ///             // `funnel` lets us avoid cloning by transforming &mut Vec<_> → &mut String.
223    ///             // Otherwise, we have to clone with `map_ref`.
224    ///             .funnel(|v: &mut Vec<_>| &mut v[0])
225    ///             .combine(vec![].into_collector().map(|v: Vec<_>| v.len()))
226    ///     );
227    ///
228    /// assert_eq!(concat_firsts, "a1swordswoman");
229    /// ```
230    ///
231    /// [`collect_ref`]: RefCollector::collect_ref
232    /// [`combine`]: RefCollector::combine
233    #[inline]
234    fn funnel<F, T>(self, func: F) -> Funnel<Self, T, F>
235    where
236        Self: Sized,
237        F: FnMut(&mut T) -> &mut Self::Item,
238    {
239        assert_ref_collector(Funnel::new(self, func))
240    }
241}
242
243/// A mutable reference to a collect produce nothing.
244///
245/// This is useful when you just want to feed items to a collector without
246/// finishing it.
247impl<C: RefCollector> RefCollector for &mut C {
248    #[inline]
249    fn collect_ref(&mut self, item: &mut Self::Item) -> ControlFlow<()> {
250        C::collect_ref(self, item)
251    }
252}
253
254macro_rules! dyn_impl {
255    ($($traits:ident)*) => {
256        impl<'a, T> Collector for &mut (dyn RefCollector<Item = T> $(+ $traits)* + 'a) {
257            type Item = T;
258
259            type Output = ();
260
261            #[inline]
262            fn collect(&mut self, item: Self::Item) -> ControlFlow<()> {
263                <dyn RefCollector<Item = T>>::collect(*self, item)
264            }
265
266            #[inline]
267            fn finish(self) -> Self::Output {}
268
269            // The default implementation are sufficient.
270        }
271
272        impl<'a, T> RefCollector for &mut (dyn RefCollector<Item = T> $(+ $traits)* + 'a) {
273            #[inline]
274            fn collect_ref(&mut self, item: &mut Self::Item) -> ControlFlow<()> {
275                <dyn RefCollector<Item = T>>::collect_ref(*self, item)
276            }
277        }
278    };
279}
280
281dyn_impl!();
282dyn_impl!(Send);
283dyn_impl!(Sync);
284dyn_impl!(Send Sync);
285
286fn _dyn_compatible<T>(_: &mut dyn RefCollector<Item = T>) {}
287
288fn _upcastable_to_collector<T>(x: &mut dyn RefCollector<Item = T>) -> &mut dyn Collector<Item = T> {
289    x
290}