Skip to main content

orx_parallel/extendable/
par_extend_core.rs

1use alloc::vec::Vec;
2
3/// Parallel collection support for destinations that must be populated from multiple worker threads.
4///
5/// `ParExtend` extends the standard `Extend` contract with the information needed to collect
6/// values produced concurrently and merge them back into a single destination. This is the
7/// abstraction used by the parallel iterators to assemble results without depending on a
8/// specific collection type or on a legacy common trait implementation.
9///
10/// A destination can support either arbitrary-order collection or ordered collection. In the
11/// first case, each thread accumulates a local buffer and the final merge combines those buffers
12/// into the destination. In the second case, each thread keeps index-aware entries so the final
13/// merge can restore the original ordering.
14///
15/// This is intended for parallel collection from fallible, optional, and infallible item streams,
16/// while preserving the corresponding short-circuit semantics and merge behavior.
17pub trait ParExtendCore<T>: Extend<T> {
18    /// Per-thread accumulation buffer for arbitrary-order collection.
19    type ThreadValues: Send;
20
21    /// Per-thread accumulation buffer for ordered collection, where the position of each emitted
22    /// item is known by its original index.
23    type OrderedThreadValues: Send;
24
25    /// Creates an empty buffer for a single worker thread in arbitrary-order collection mode.
26    fn new_thread_values() -> Self::ThreadValues;
27
28    /// Creates an empty buffer for a single worker thread in ordered collection mode.
29    fn new_ordered_thread_values() -> Self::OrderedThreadValues;
30
31    // thread collect
32
33    /// Adds a single value into a thread-local arbitrary-order buffer.
34    fn add_thread_value(collected: &mut Self::ThreadValues, value: T);
35
36    /// Adds all values from an iterator into a thread-local arbitrary-order buffer.
37    fn add_thread_values(collected: &mut Self::ThreadValues, values: impl IntoIterator<Item = T>);
38
39    /// Adds a single value at the given index to a thread-local ordered buffer.
40    fn add_ordered_thread_value(collected: &mut Self::OrderedThreadValues, idx: usize, value: T);
41
42    /// Adds all values from an iterator into a thread-local ordered buffer, assigning the original
43    /// indices to each entry.
44    fn add_ordered_thread_values(
45        collected: &mut Self::OrderedThreadValues,
46        idx: usize,
47        values: impl IntoIterator<Item = T>,
48    );
49
50    // opt: thread collect
51
52    /// Consumes an iterator of optional values and stores only the `Some` items in a thread-local
53    /// arbitrary-order buffer.
54    fn add_thread_optionals(
55        collected: &mut Self::ThreadValues,
56        values: impl IntoIterator<Item = Option<T>>,
57    ) -> Option<()> {
58        for value in values {
59            Self::add_thread_value(collected, value?);
60        }
61        Some(())
62    }
63
64    /// Consumes an iterator of optional values and stores only the `Some` items in a thread-local
65    /// ordered buffer.
66    fn add_ordered_thread_optionals(
67        collected: &mut Self::OrderedThreadValues,
68        idx: usize,
69        values: impl IntoIterator<Item = Option<T>>,
70    ) -> Option<()>;
71
72    // res: thread collect
73
74    /// Consumes an iterator of fallible values and stores only the successful items in a
75    /// thread-local arbitrary-order buffer.
76    fn add_thread_fallibles<E>(
77        collected: &mut Self::ThreadValues,
78        values: impl IntoIterator<Item = Result<T, E>>,
79    ) -> Result<(), E> {
80        for value in values {
81            Self::add_thread_value(collected, value?)
82        }
83        Ok(())
84    }
85
86    /// Consumes an iterator of fallible values and stores only the successful items in a
87    /// thread-local ordered buffer.
88    fn add_ordered_thread_fallibles<E>(
89        collected: &mut Self::OrderedThreadValues,
90        idx: usize,
91        values: impl IntoIterator<Item = Result<T, E>>,
92    ) -> Result<(), E>;
93
94    // add
95
96    /// Inserts a single value into the destination collection.
97    fn add_one(&mut self, value: T);
98
99    // extend
100
101    /// Extends the destination with optional items, stopping early if an `Option::None` is
102    /// encountered while preserving the short-circuit semantics used by the parallel APIs.
103    fn extend_optionals(&mut self, optionals: impl IntoIterator<Item = Option<T>>) -> Option<()> {
104        for value in optionals {
105            self.add_one(value?);
106        }
107        Some(())
108    }
109
110    /// Extends the destination with fallible items, propagating the first error encountered.
111    fn extend_fallibles<E>(
112        &mut self,
113        fallibles: impl IntoIterator<Item = Result<T, E>>,
114    ) -> Result<(), E> {
115        for value in fallibles {
116            self.add_one(value?);
117        }
118        Ok(())
119    }
120
121    // extend - merge
122
123    /// Merges thread-local arbitrary-order results into the destination collection.
124    fn extend_merge_infallibles(&mut self, thread_results: Vec<Self::ThreadValues>);
125
126    /// Merges thread-local ordered results into the destination collection, restoring the original
127    /// item order before the final collection is completed.
128    fn extend_merge_ordered_infallibles(&mut self, thread_results: Vec<Self::OrderedThreadValues>);
129
130    /// Merges arbitrary-order optional thread results, returning `None` if any thread reported a
131    /// stop condition.
132    fn extend_merge_optionals(
133        &mut self,
134        thread_results: Vec<Option<Self::ThreadValues>>,
135    ) -> Option<()> {
136        let infallibles: Option<Vec<Self::ThreadValues>> = thread_results.into_iter().collect();
137        self.extend_merge_infallibles(infallibles?);
138        Some(())
139    }
140
141    /// Merges ordered optional thread results, returning `None` if any thread reported a stop
142    /// condition.
143    fn extend_merge_ordered_optionals(
144        &mut self,
145        thread_results: Vec<Option<Self::OrderedThreadValues>>,
146    ) -> Option<()> {
147        let infallibles: Option<Vec<Self::OrderedThreadValues>> =
148            thread_results.into_iter().collect();
149        self.extend_merge_ordered_infallibles(infallibles?);
150        Some(())
151    }
152
153    /// Merges arbitrary-order fallible thread results, propagating the first error encountered.
154    fn extend_merge_fallibles<E>(
155        &mut self,
156        thread_results: Vec<Result<Self::ThreadValues, E>>,
157    ) -> Result<(), E> {
158        let infallibles: Result<Vec<Self::ThreadValues>, E> = thread_results.into_iter().collect();
159        self.extend_merge_infallibles(infallibles?);
160        Ok(())
161    }
162
163    /// Merges ordered fallible thread results, propagating the first error encountered while also
164    /// restoring the original index ordering.
165    fn extend_merge_ordered_fallibles<E>(
166        &mut self,
167        thread_results: Vec<Result<Self::OrderedThreadValues, E>>,
168    ) -> Result<(), E> {
169        let infallibles: Result<Vec<Self::OrderedThreadValues>, E> =
170            thread_results.into_iter().collect();
171        self.extend_merge_ordered_infallibles(infallibles?);
172        Ok(())
173    }
174}