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}