Skip to main content

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}