blake3/join.rs
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.
22pub 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.
37pub enum SerialJoin {}
38
39impl 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")]
58pub enum RayonJoin {}
59
60#[cfg(feature = "rayon")]
61impl 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)]
75mod 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}