use crossbeam::channel::{Receiver, Sender}; use std::sync::mpsc; #[derive(Clone)] /// A generic job dispatcher struct that allows sending jobs of type `T` and receiving results of type `V` using message passing. pub struct JobDispatcher { sender: Sender>, } pub struct JobResult(std::sync::mpsc::Receiver); impl JobResult { /// Wait for the Result of a Job. pub fn wait(self) -> V { self.0.recv().unwrap() } } impl JobDispatcher { /// Creates a new instance of `JobDispatcher` and returns a tuple that contains it and a receiver end for `JobOrder`s. /// # Example: /// ``` /// use jobdispatcher::*; /// // Create job dispatcher /// let (dispatcher, recv) = JobDispatcher::::new(); /// /// // Worker Thread /// std::thread::spawn(move || { /// for job in recv { /// let result = job.param + 1; /// job.done(result); /// } /// }); /// /// // Usage /// let result = dispatcher.send(3); /// assert_eq!(result, 4); /// ``` #[must_use] pub fn new() -> (Self, Receiver>) { let (sender, receiver) = crossbeam::channel::bounded(12); (Self { sender: sender }, receiver) } /// Sends a job of type `T` to the job dispatcher and waits for its result of type `V`. /// Returns the result of the job once it has been processed. /// # Panics /// This function panics when the `JobOrder` struct gets out of scope without returning a finished result. /// Additionally if the internal `Mutex` is poisoned, this function will panic as well. pub fn send(&self, param: T) -> V { let (tx, rx) = mpsc::channel(); let job_order = JobOrder::new(param, move |ret| { tx.send(ret).unwrap(); }); self.sender.send(job_order).unwrap(); rx.recv().unwrap() } pub fn send_async(&self, param: T) -> JobResult { let (tx, rx) = mpsc::channel(); let job_order = JobOrder::new(param, move |ret| { tx.send(ret).unwrap(); }); self.sender.send(job_order).unwrap(); JobResult(rx) } /// Sends a job of type `T` to the job dispatcher and waits for its result of type `V`. /// Returns `Some(V)` when the job returns an result, `None` if somehow nothing was returned or the internal `Mutex` is poisoned. pub fn try_send(&self, param: T) -> Option { let (tx, rx) = mpsc::channel(); let job_order = JobOrder::new(param, move |ret| { tx.send(ret).unwrap(); }); self.sender.send(job_order).ok()?; rx.recv().ok() } } /// A struct that represents a job order that encapsulates a job of type `T` and its result of type `V`, along with a callback function that will send the result back to the job origin. pub struct JobOrder { /// The job parameter of type `T`. pub param: T, callback: Box, } impl JobOrder { /// Creates a new `JobOrder` instance with the specified job parameter `param` of type `T` and a callback function that takes the job result of type `V` as an argument. #[must_use] fn new(param: T, callback: impl FnOnce(V) + Send + 'static) -> Self { Self { param, callback: Box::new(callback), } } /// Send the result of the `JobOrder` back to it's origin pub fn done(self, val: V) { (self.callback)(val); } }