orx_parallel/into_parallel/into_par_rec_iter.rs
1use crate::infallible::ParRecIter;
2use crate::infallible::xap_variants::Id;
3use crate::runner::default_runner;
4
5/// Creates an infallible parallel iterator for dynamically expanding recursive workloads.
6///
7/// Unlike flat sources such as slices or ranges, recursive workloads discover new items while
8/// existing items are being processed. `initial_elements` provides the starting frontier, and
9/// `extend` is called for each visited item to produce its children or follow-up work.
10///
11/// Despite parallel execution, recursive traversal can be deterministic. With
12/// [`IterationOrder::Ordered`] (the default), order-sensitive operations use breadth-first order,
13/// level by level and left-to-right following input and child generation order.
14///
15/// # Example
16///
17/// ```
18/// use orx_parallel::*;
19///
20/// // A small rooted tree represented as adjacency lists.
21/// // Node 0 is the root.
22/// let children: Vec<Vec<usize>> = vec![
23/// vec![1, 2], // children of 0
24/// vec![3, 4], // children of 1
25/// vec![5], // children of 2
26/// vec![],
27/// vec![],
28/// vec![],
29/// ];
30///
31/// let visited: Vec<_> = par_recursive([0usize], |node| children[*node].iter().copied())
32/// .map(|x| 2 * x + 1)
33/// .collect();
34///
35/// // Ordered traversal is deterministic and breadth-first by default.
36/// assert_eq!(visited, vec![1, 3, 5, 7, 9, 11]);
37/// ```
38///
39/// [`IterationOrder::Ordered`]: crate::IterationOrder::Ordered
40pub fn par_recursive<I, C, F>(initial_elements: I, extend: F) -> ParRecIter<I, Id<I::Item>, C, F>
41where
42 I: IntoIterator,
43 C: IntoIterator<Item = I::Item>,
44 F: Fn(&I::Item) -> C + Send + Copy,
45{
46 ParRecIter::new(
47 initial_elements,
48 Id::new(),
49 default_runner(),
50 Default::default(),
51 extend,
52 )
53}