#![doc(html_root_url = "https://docs.rs/halt")]
#![deny(missing_docs)]
use std::io::{self, Read, Write};
use std::sync::{Arc, Condvar, Mutex, Weak};
use Status::{Paused, Running, Stopped};
pub fn new<T>(inner: T) -> Halt<T> {
Halt::from(inner)
}
#[derive(Debug, Default)]
pub struct Halt<T> {
inner: T,
state: Arc<State>,
}
impl<T> Halt<T> {
pub fn remote(&self) -> Remote {
Remote {
state: Arc::downgrade(&self.state),
}
}
pub fn is_running(&self) -> bool {
self.state.is_running()
}
pub fn is_paused(&self) -> bool {
self.state.is_paused()
}
pub fn is_stopped(&self) -> bool {
self.state.is_stopped()
}
pub fn get_ref(&self) -> &T {
&self.inner
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
fn wait_if_paused(&self) {
let guard = self.state.status.lock().unwrap();
let _guard = self
.state
.condvar
.wait_while(guard, |status| *status == Paused)
.unwrap();
}
}
impl<T> From<T> for Halt<T> {
fn from(inner: T) -> Self {
Halt {
inner,
state: Arc::default(),
}
}
}
impl<I: Iterator> Iterator for Halt<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.wait_if_paused();
if self.is_stopped() {
None
} else {
self.inner.next()
}
}
}
impl<I: DoubleEndedIterator> DoubleEndedIterator for Halt<I> {
fn next_back(&mut self) -> Option<Self::Item> {
self.wait_if_paused();
if self.is_stopped() {
None
} else {
self.inner.next_back()
}
}
}
impl<A, I: Extend<A>> Extend<A> for Halt<I> {
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
self.inner.extend(iter);
}
}
impl<R: Read> Read for Halt<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.wait_if_paused();
if self.is_stopped() {
Ok(0)
} else {
self.inner.read(buf)
}
}
}
impl<W: Write> Write for Halt<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.wait_if_paused();
if self.is_stopped() {
Ok(0)
} else {
self.inner.write(buf)
}
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
enum Status {
Running,
Paused,
Stopped,
}
impl Default for Status {
fn default() -> Self {
Running
}
}
#[derive(Debug, Default)]
struct State {
status: Mutex<Status>,
condvar: Condvar,
}
impl State {
fn is_running(&self) -> bool {
self.status
.lock()
.map_or(false, |status| *status == Running)
}
fn is_paused(&self) -> bool {
self.status.lock().map_or(false, |status| *status == Paused)
}
fn is_stopped(&self) -> bool {
self.status
.lock()
.map_or(false, |status| *status == Stopped)
}
}
#[derive(Clone, Debug)]
pub struct Remote {
state: Weak<State>,
}
impl Remote {
pub fn resume(&self) -> bool {
self.set_and_notify(Running)
}
pub fn pause(&self) -> bool {
self.set_and_notify(Paused)
}
pub fn stop(&self) -> bool {
self.set_and_notify(Stopped)
}
pub fn is_valid(&self) -> bool {
self.state.strong_count() != 0
}
pub fn is_running(&self) -> bool {
self.state
.upgrade()
.map_or(false, |state| state.is_running())
}
pub fn is_paused(&self) -> bool {
self.state
.upgrade()
.map_or(false, |state| state.is_paused())
}
pub fn is_stopped(&self) -> bool {
self.state
.upgrade()
.map_or(false, |state| state.is_stopped())
}
fn set_and_notify(&self, new: Status) -> bool {
self.state.upgrade().map_or(false, |state| {
let mut guard = state.status.lock().unwrap();
let status = &mut *guard;
let need_to_notify = *status == Paused && *status != new;
*status = new;
drop(guard);
if need_to_notify {
state.condvar.notify_all();
}
true
})
}
}