meli/melib/src/async.rs

194 lines
5.4 KiB
Rust
Raw Normal View History

2018-08-07 15:01:15 +03:00
/*
* meli - async module
*
* Copyright 2017 Manos Pitsidianakis
*
* This file is part of meli.
*
* meli is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* meli is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
2018-08-06 22:20:34 +03:00
/*!
* Primitive Async/Wait implementation.
*
* To create an Async promise, create an AsyncBuilder. Ask for its channel receiver/sender with
* `tx` and `rx` methods to pass them in your worker's closure. Build an `Async<T>` with your
* `JoinHandle<T>`. The thread must communicate with the `Async<T>` object via `AsyncStatus`
* messages.
*
* When `Async<T>` receives `AsyncStatus::Finished` it joins the thread and takes its value which
* can be extracted with `extract`.
*/
2018-08-03 13:46:08 +03:00
use chan;
2018-10-14 19:49:16 +03:00
use std::fmt;
use std::sync::Arc;
#[derive(Clone)]
pub struct Work(pub Arc<Box<dyn Fn() -> ()>>);
impl Work {
pub fn compute(&self) {
(self.0)();
}
}
impl fmt::Debug for Work {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Work object")
}
}
unsafe impl Send for Work {}
unsafe impl Sync for Work {}
2018-08-03 13:46:08 +03:00
2018-08-06 22:20:34 +03:00
/// Messages to pass between `Async<T>` owner and its worker thread.
2018-10-14 19:49:16 +03:00
#[derive(Clone)]
pub enum AsyncStatus<T> {
2018-08-03 13:46:08 +03:00
NoUpdate,
2018-10-14 19:49:16 +03:00
Payload(T),
2018-08-03 13:46:08 +03:00
Finished,
2018-08-06 22:20:34 +03:00
///The number may hold whatever meaning the user chooses.
2018-08-03 13:46:08 +03:00
ProgressReport(usize),
}
2018-10-14 19:49:16 +03:00
impl<T> fmt::Debug for AsyncStatus<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AsyncStatus::NoUpdate => write!(f, "AsyncStatus<T>::NoUpdate"),
AsyncStatus::Payload(_) => write!(f, "AsyncStatus<T>::Payload(_)"),
AsyncStatus::Finished => write!(f, "AsyncStatus<T>::Finished"),
AsyncStatus::ProgressReport(u) => write!(f, "AsyncStatus<T>::ProgressReport({})", u),
}
}
}
2018-08-06 22:20:34 +03:00
/// A builder object for `Async<T>`
2018-10-14 19:49:16 +03:00
#[derive(Debug, Clone)]
pub struct AsyncBuilder<T> {
tx: chan::Sender<AsyncStatus<T>>,
rx: chan::Receiver<AsyncStatus<T>>,
2018-08-03 13:46:08 +03:00
}
2018-10-14 19:49:16 +03:00
#[derive(Debug, Clone)]
2018-08-03 13:46:08 +03:00
pub struct Async<T> {
value: Option<T>,
2018-10-14 19:49:16 +03:00
work: Work,
active: bool,
tx: chan::Sender<AsyncStatus<T>>,
rx: chan::Receiver<AsyncStatus<T>>,
2018-08-03 13:46:08 +03:00
}
2018-10-14 19:49:16 +03:00
impl<T> Default for AsyncBuilder<T> {
2018-08-23 15:36:52 +03:00
fn default() -> Self {
2018-10-14 19:49:16 +03:00
AsyncBuilder::<T>::new()
2018-08-23 15:36:52 +03:00
}
}
2018-10-14 19:49:16 +03:00
impl<T> AsyncBuilder<T> {
2018-08-03 13:46:08 +03:00
pub fn new() -> Self {
2018-10-14 19:49:16 +03:00
let (sender, receiver) = chan::sync(8 * ::std::mem::size_of::<AsyncStatus<T>>());
2018-08-03 13:46:08 +03:00
AsyncBuilder {
tx: sender,
rx: receiver,
}
}
2018-08-06 22:20:34 +03:00
/// Returns the sender object of the promise's channel.
2018-10-14 19:49:16 +03:00
pub fn tx(&mut self) -> chan::Sender<AsyncStatus<T>> {
2018-08-03 13:46:08 +03:00
self.tx.clone()
}
2018-08-06 22:20:34 +03:00
/// Returns the receiver object of the promise's channel.
2018-10-14 19:49:16 +03:00
pub fn rx(&mut self) -> chan::Receiver<AsyncStatus<T>> {
2018-08-03 13:46:08 +03:00
self.rx.clone()
}
2018-08-06 22:20:34 +03:00
/// Returns an `Async<T>` object that contains a `Thread` join handle that returns a `T`
2018-10-14 19:49:16 +03:00
pub fn build(self, work: Box<dyn Fn() -> ()>) -> Async<T> {
2018-08-03 13:46:08 +03:00
Async {
2018-10-14 19:49:16 +03:00
work: Work(Arc::new(work)),
2018-08-03 13:46:08 +03:00
value: None,
tx: self.tx,
rx: self.rx,
2018-10-14 19:49:16 +03:00
active: false,
2018-08-03 13:46:08 +03:00
}
}
}
impl<T> Async<T> {
2018-08-06 22:20:34 +03:00
/// Consumes `self` and returns the computed value. Will panic if computation hasn't finished.
2018-08-03 13:46:08 +03:00
pub fn extract(self) -> T {
self.value.unwrap()
}
2018-10-14 19:49:16 +03:00
pub fn work(&mut self) -> Option<Work> {
if !self.active {
self.active = true;
Some(self.work.clone())
} else {
None
}
}
/// Returns the sender object of the promise's channel.
pub fn tx(&mut self) -> chan::Sender<AsyncStatus<T>> {
self.tx.clone()
}
2018-08-07 15:01:15 +03:00
/// Polls worker thread and returns result.
2018-10-14 19:49:16 +03:00
pub fn poll(&mut self) -> Result<AsyncStatus<T>, ()> {
2018-08-03 13:46:08 +03:00
if self.value.is_some() {
return Ok(AsyncStatus::Finished);
}
//self.tx.send(true);
let rx = &self.rx;
2018-10-14 19:49:16 +03:00
let result: T;
2018-08-03 13:46:08 +03:00
chan_select! {
default => {
return Ok(AsyncStatus::NoUpdate);
},
rx.recv() -> r => {
match r {
2018-10-14 19:49:16 +03:00
Some(AsyncStatus::Payload(payload)) => {
result = payload;
2018-08-03 13:46:08 +03:00
},
Some(a) => {
return Ok(a);
}
_ => {
return Err(());
},
}
},
2018-10-14 19:49:16 +03:00
};
self.value = Some(result);
2018-08-23 15:36:52 +03:00
Ok(AsyncStatus::Finished)
2018-08-03 13:46:08 +03:00
}
2018-09-17 07:48:50 +03:00
/// Blocks until thread joins.
2018-10-14 19:49:16 +03:00
pub fn join(&mut self) {
let result: T;
let rx = &self.rx;
loop {
chan_select! {
rx.recv() -> r => {
match r {
Some(AsyncStatus::Payload(payload)) => {
result = payload;
break;
},
_ => continue,
}
}
}
}
self.value = Some(result);
2018-09-17 07:48:50 +03:00
}
2018-08-03 13:46:08 +03:00
}