use std::{
sync::mpsc::Receiver,
cell::Cell
};
/// Water Bottle.
///
/// The Bottle ***must*** be held and used, otherwise it will [`Shatter`].
///
/// Allows to access Water that was produced by melting Ice.
///
/// [`Shatter`]: struct.Bottle.html#impl-Drop
pub struct Bottle<W>(Receiver<W>, Cell<bool>);
impl<W> Bottle<W> {
pub(crate) fn new(water: Receiver<W>) -> Bottle<W> {
Bottle(water, Cell::new(false))
}
/// Opens the Bottle, granting access to Water.
///
/// The Bottle is consumed in the process.
///
/// # Blocking
///
/// This operation blocks till the Heater is done melting Ice.
///
/// # Panics
///
/// * When the Bottle has already been opened.
/// * When the Bottle is Poisoned<sup>1</sup>. Poisoning<sup>1</sup> happens when Heater
/// melting the Ice fails. Irrecoverable.
///
/// ---
///
/// <sup>1</sup> - Not to be confused with [`Poisoning of the Mutex`], although Bottle is
/// Poisoned because of a very similar reason - panic in a thread.
///
/// [`Poisoning of the Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#poisoning
pub fn open(&self) -> W {
if self.1.get() {
panic!("Tried to open an already opened bottle");
} else {
self.1.set(true);
}
self.0
.recv()
.expect("Tried to open a Poisoned bottle")
}
}
impl<T> Drop for Bottle<T> {
/// Drops the Bottle.
///
/// # Panics
///
/// When Bottle is dropped without ever being used. This causes it to shatter.
///
/// It is completely user's responsibility to ensure that bottle is not dropped without
/// being used.
fn drop(&mut self) {
assert!(self.1.get(), "Bottle dropped without ever being opened *Shatters*");
}
}