use std::sync::{Condvar, Mutex, PoisonError};
use crate::errors::Error;
use crate::transport::common::lock;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum State {
Connected,
Disconnected,
ShutDown,
}
#[derive(Debug)]
pub(crate) struct ConnectionSignal {
state: Mutex<State>,
changed: Condvar,
}
impl Default for ConnectionSignal {
fn default() -> Self {
Self {
state: Mutex::new(State::Connected),
changed: Condvar::new(),
}
}
}
impl ConnectionSignal {
pub(crate) fn is_connected(&self) -> bool {
*lock(&self.state) == State::Connected
}
pub(crate) fn set_connected(&self) {
self.set(State::Connected);
}
pub(crate) fn set_disconnected(&self) {
self.set(State::Disconnected);
}
pub(crate) fn shutdown(&self) {
*lock(&self.state) = State::ShutDown;
self.changed.notify_all();
}
pub(crate) fn wait_connected(&self) -> Result<(), Error> {
let mut state = lock(&self.state);
loop {
match *state {
State::Connected => return Ok(()),
State::ShutDown => return Err(Error::Shutdown),
State::Disconnected => state = self.changed.wait(state).unwrap_or_else(PoisonError::into_inner),
}
}
}
fn set(&self, new_state: State) {
let mut state = lock(&self.state);
if *state == State::ShutDown {
return;
}
*state = new_state;
self.changed.notify_all();
}
}
#[cfg(test)]
#[path = "connection_signal_tests.rs"]
mod tests;