ice_threads/
melter.rs

1use std::sync::{
2    Arc, Mutex,
3    mpsc,
4    mpsc::Sender
5};
6
7use crate::{
8    Bottle,
9    Heater,
10    Ice, IceBox,
11};
12
13
14
15/// Ice Melter.
16///
17/// This struct is responsible for queueing all the Ice to be molten using it's Heaters.
18pub struct Melter {
19    heaters: Vec<Heater>,
20    ice_boxes: Sender<IceBox>
21}
22
23impl Melter {
24    /// Creates a new Ice Melter with specified amount of Heaters.
25    ///
26    /// # Panics
27    ///
28    /// When count is zero.
29    pub fn new(count: usize) -> Melter {
30        assert!(count > 0, "ice_threads::Melter::new -> Heater count must be greater than 0!");
31
32        let mut heaters = Vec::with_capacity(count);
33
34        let (sender, receiver) = mpsc::channel();
35
36        let receiver = Arc::new(Mutex::new(receiver));
37        for _ in 0..count {
38            heaters.push(Heater::new(receiver.clone()));
39        }
40
41        Melter {
42            heaters,
43            ice_boxes: sender
44        }
45    }
46
47    /// Enqueues Ice to be molten.
48    ///
49    /// Returns a Bottle which will be filled with Water coming from given Ice.
50    ///
51    /// # Panics
52    ///
53    /// When all Heaters fail.
54    ///
55    /// This should generally be impossible unless the user's code happens to have a bug, panics
56    /// and doesn't open the poisoned [`Bottle`] that would stop the process earlier.
57    ///
58    /// [`Bottle`]: struct.Bottle.html
59    #[must_use]
60    pub fn melt<I, W>(&self, ice: I) -> Bottle<W>
61    where
62        I: FnOnce() -> W + Send + 'static,
63        W: Send + 'static
64    {
65        let (sender, receiver) = mpsc::channel::<W>();
66        let ice_box = IceBox::Some(
67            Ice::new(move || {
68                sender.send(ice()).ok();
69            })
70        );
71
72        self.ice_boxes
73            .send(ice_box)
74            .expect("ice_threads::Melter::melt -> Failed to send Ice box to a Heater group");
75
76        Bottle::new(receiver)
77    }
78}
79
80impl Drop for Melter {
81    /// Gracefully powers down all Heaters.
82    fn drop(&mut self) {
83        for _ in &self.heaters {
84            if self.ice_boxes.send(IceBox::None).is_err() {
85                break;
86            }
87        }
88
89        for heater in &mut self.heaters {
90            if let Some(core) = heater.take_core() {
91                core.join().ok();
92            }
93        }
94    }
95}