par_core/
lib.rs

1//! # par-core
2//!
3//! A wrapper for various parallelization library for Rust.
4//! This crate currently supports
5//!
6//! - [`chili`](https://github.com/dragostis/chili)
7//! - [`rayon`](https://github.com/rayon-rs/rayon)
8//! - Disable parallelization.
9//!
10//! # Usage
11//!
12//! If you are developing a library, you should not force the parallelization
13//! library, and let the users choose the parallelization library.
14//!
15//! ## Final application
16//!
17//! If you are developing a final application, you can use cargo feature to
18//! select the parallelization library.
19//!
20//! ### `chili`
21//!
22//! ```toml
23//! [dependencies]
24//! par-core = { version = "1.0.1", features = ["chili"] }
25//! ```
26//!
27//! ### `rayon`
28//!
29//! ```toml
30//! [dependencies]
31//! par-core = { version = "1.0.1", features = ["rayon"] }
32//! ```
33//!
34//! ### Disable parallelization
35//!
36//! ```toml
37//! [dependencies]
38//! par-core = { version = "1.0.1", default-features = false }
39//! ```
40//!
41//! ## Library developers
42//!
43//! If you are developing a library, you can simply depend on `par-core` without
44//! any features. **Note**: To prevent a small mistake of end-user making the
45//! appplication slower, `par-core` emits a error message using a default
46//! feature. So if you are a library developer, you should specify
47//! `default-features = false`.
48//!
49//! ```toml
50//! [dependencies]
51//! par-core = { version = "1.0.1", default-features = false }
52//! ```
53
54#[cfg(all(not(feature = "chili"), not(feature = "rayon"), feature = "parallel"))]
55compile_error!("You must enable `chili` or `rayon` feature if you want to use `parallel` feature");
56
57#[cfg(all(feature = "chili", feature = "rayon"))]
58compile_error!("You must enable `chili` or `rayon` feature, not both");
59
60#[cfg(feature = "chili")]
61mod par_chili {
62    use std::{cell::RefCell, mem::transmute};
63
64    use chili::Scope;
65
66    thread_local! {
67        static SCOPE: RefCell<Option<&'static mut Scope<'static>>> = Default::default();
68    }
69
70    #[inline]
71    fn join_scoped<A, B, RA, RB>(scope: &mut Scope<'_>, oper_a: A, oper_b: B) -> (RA, RB)
72    where
73        A: Send + FnOnce() -> RA,
74        B: Send + FnOnce() -> RB,
75        RA: Send,
76        RB: Send,
77    {
78        scope.join(
79            |scope| {
80                let old_scope = SCOPE.take();
81                // SATETY: it will be only accessed during `oper_a`
82                SCOPE.set(Some(unsafe { transmute::<&mut Scope, &mut Scope>(scope) }));
83
84                let ra = oper_a();
85                SCOPE.set(old_scope);
86
87                ra
88            },
89            |scope| {
90                let old_scope = SCOPE.take();
91                // SATETY: it will be only accessed during `oper_b`
92                SCOPE.set(Some(unsafe { transmute::<&mut Scope, &mut Scope>(scope) }));
93
94                let rb = oper_b();
95                SCOPE.set(old_scope);
96
97                rb
98            },
99        )
100    }
101
102    #[inline]
103    pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
104    where
105        A: Send + FnOnce() -> RA,
106        B: Send + FnOnce() -> RB,
107        RA: Send,
108        RB: Send,
109    {
110        let old_scope: Option<&mut Scope<'_>> = SCOPE.take();
111        match old_scope {
112            Some(scope) => {
113                let (ra, rb) = join_scoped(scope, oper_a, oper_b);
114                SCOPE.set(Some(scope));
115                (ra, rb)
116            }
117            None => join_scoped(&mut Scope::global(), oper_a, oper_b),
118        }
119    }
120}
121
122pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
123where
124    A: Send + FnOnce() -> RA,
125    B: Send + FnOnce() -> RB,
126    RA: Send,
127    RB: Send,
128{
129    #[cfg(feature = "chili")]
130    let (ra, rb) = par_chili::join(oper_a, oper_b);
131
132    #[cfg(feature = "rayon")]
133    let (ra, rb) = rayon::join(oper_a, oper_b);
134
135    #[cfg(not(feature = "parallel"))]
136    let (ra, rb) = (oper_a(), oper_b());
137
138    (ra, rb)
139}