1 | //! The multi-threading abstractions used by `Hasher::update_with_join`. |
2 | //! |
3 | //! Different implementations of the `Join` trait determine whether |
4 | //! `Hasher::update_with_join` performs multi-threading on sufficiently large |
5 | //! inputs. The `SerialJoin` implementation is single-threaded, and the |
6 | //! `RayonJoin` implementation (gated by the `rayon` feature) is multi-threaded. |
7 | //! Interfaces other than `Hasher::update_with_join`, like [`hash`](crate::hash) |
8 | //! and [`Hasher::update`](crate::Hasher::update), always use `SerialJoin` |
9 | //! internally. |
10 | //! |
11 | //! The `Join` trait is an almost exact copy of the [`rayon::join`] API, and |
12 | //! `RayonJoin` is the only non-trivial implementation. Previously this trait |
13 | //! was public, but currently it's been re-privatized, as it's both 1) of no |
14 | //! value to most callers and 2) a pretty big implementation detail to commit |
15 | //! to. |
16 | //! |
17 | //! [`rayon::join`]: https://docs.rs/rayon/1.3.0/rayon/fn.join.html |
18 | |
19 | /// The trait that abstracts over single-threaded and multi-threaded recursion. |
20 | /// |
21 | /// See the [`join` module docs](index.html) for more details. |
22 | pub trait Join { |
23 | fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) |
24 | where |
25 | A: FnOnce() -> RA + Send, |
26 | B: FnOnce() -> RB + Send, |
27 | RA: Send, |
28 | RB: Send; |
29 | } |
30 | |
31 | /// The trivial, serial implementation of `Join`. The left and right sides are |
32 | /// executed one after the other, on the calling thread. The standalone hashing |
33 | /// functions and the `Hasher::update` method use this implementation |
34 | /// internally. |
35 | /// |
36 | /// See the [`join` module docs](index.html) for more details. |
37 | pub enum SerialJoin {} |
38 | |
39 | impl Join for SerialJoin { |
40 | #[inline ] |
41 | fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) |
42 | where |
43 | A: FnOnce() -> RA + Send, |
44 | B: FnOnce() -> RB + Send, |
45 | RA: Send, |
46 | RB: Send, |
47 | { |
48 | (oper_a(), oper_b()) |
49 | } |
50 | } |
51 | |
52 | /// The Rayon-based implementation of `Join`. The left and right sides are |
53 | /// executed on the Rayon thread pool, potentially in parallel. This |
54 | /// implementation is gated by the `rayon` feature, which is off by default. |
55 | /// |
56 | /// See the [`join` module docs](index.html) for more details. |
57 | #[cfg (feature = "rayon" )] |
58 | pub enum RayonJoin {} |
59 | |
60 | #[cfg (feature = "rayon" )] |
61 | impl Join for RayonJoin { |
62 | #[inline ] |
63 | fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) |
64 | where |
65 | A: FnOnce() -> RA + Send, |
66 | B: FnOnce() -> RB + Send, |
67 | RA: Send, |
68 | RB: Send, |
69 | { |
70 | rayon_core::join(oper_a, oper_b) |
71 | } |
72 | } |
73 | |
74 | #[cfg (test)] |
75 | mod test { |
76 | use super::*; |
77 | |
78 | #[test ] |
79 | fn test_serial_join() { |
80 | let oper_a = || 1 + 1; |
81 | let oper_b = || 2 + 2; |
82 | assert_eq!((2, 4), SerialJoin::join(oper_a, oper_b)); |
83 | } |
84 | |
85 | #[test ] |
86 | #[cfg (feature = "rayon" )] |
87 | fn test_rayon_join() { |
88 | let oper_a = || 1 + 1; |
89 | let oper_b = || 2 + 2; |
90 | assert_eq!((2, 4), RayonJoin::join(oper_a, oper_b)); |
91 | } |
92 | } |
93 | |