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 { join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) where A: FnOnce() -> RA + Send, B: FnOnce() -> RB + Send, RA: Send, RB: Send23 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] join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) where A: FnOnce() -> RA + Send, B: FnOnce() -> RB + Send, RA: Send, RB: Send,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] join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) where A: FnOnce() -> RA + Send, B: FnOnce() -> RB + Send, RA: Send, RB: Send,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::join(oper_a, oper_b) 71 } 72 } 73 74 #[cfg(test)] 75 mod test { 76 use super::*; 77 78 #[test] test_serial_join()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")] test_rayon_join()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