response values

progress
Avril 4 years ago
parent 6a2570a0c4
commit 88defc530e
Signed by: flanchan
GPG Key ID: 284488987C31F630

74
Cargo.lock generated

@ -314,6 +314,17 @@ dependencies = [
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gimli"
version = "0.22.0"
@ -553,6 +564,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "pretty_env_logger"
version = "0.4.0"
@ -599,6 +616,47 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
@ -870,6 +928,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "uuid"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
dependencies = [
"rand",
]
[[package]]
name = "version_check"
version = "0.9.2"
@ -893,8 +960,15 @@ dependencies = [
"smallmap",
"termprogress",
"tokio",
"uuid",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.2.8"

@ -31,6 +31,7 @@ smallmap = "^1.1.6"
log = "0.4.11"
pretty_env_logger = "0.4.0"
termprogress = "0.3.4"
uuid = {version = "0.8.1", features=["v4"]}
[build-dependencies]
rustc_version = "0.2"

@ -11,6 +11,33 @@ use std::{
num::NonZeroU8,
};
pub trait JoinStrsExt: Sized
{
/// Join an iterator of `str` with a seperator
fn join(self, with: &str) -> String;
}
impl<T,I> JoinStrsExt for I
where I: Iterator<Item=T>,
T: AsRef<str>
{
fn join(self, with: &str) -> String
{
let mut output = String::new();
let mut first=true;
for string in self
{
if !first {
output.push_str(with);
}
let string = string.as_ref();
output.push_str(string);
first=false;
}
output
}
}
pub use dedup::DedupIterExt;
/// Iterator that maps `T` -> `U`
@ -188,3 +215,11 @@ impl<T,E> IgnoreResultExt for Result<T,E>
//Do nothing
}
}
impl<T> IgnoreResultExt for Option<T>
{
#[inline(always)] fn ignore(self)
{
//Do nothing
}
}

@ -1,4 +1,5 @@
#![cfg_attr(nightly, feature(never_type))]
#![cfg_attr(nightly, feature(never_type))]
#![cfg_attr(nightly, feature(drain_filter))]
#![allow(dead_code)]

@ -26,6 +26,8 @@ use std::{
error,
};
mod tasklist;
/// Command to send to worker task.
#[derive(Debug, Clone)]
pub enum CommandKind
@ -41,6 +43,8 @@ pub enum CommandKind
Many(Vec<CommandKind>),
}
pub type Response = Option<Box<dyn std::any::Any + Send+ Sync + 'static>>;
#[derive(Debug)]
enum CommandIter
{
@ -77,6 +81,7 @@ impl CommandKind
/// Enumerate all possible commands if this is `Many`.
///
/// The outputs may still contain `Many`.
//TODO: Make this work recursively
fn enumerate(self) -> CommandIter
{
match self {
@ -90,7 +95,7 @@ impl CommandKind
pub struct BarRef<B>(Arc<RwLock<B>>);
#[derive(Debug)]
struct Command(CommandKind, oneshot::Sender<()>);
struct Command(CommandKind, oneshot::Sender<Response>);
/// The bar's state
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
@ -148,7 +153,7 @@ impl<B: ProgressBar> Handle<B>
/// Send a command to the worker.
///
/// Returns a future that completes to `Ok` when the worker successfully processes the command, and `Err` if the worker exits before processing it
pub async fn send_command(&mut self, command: CommandKind) -> Result<impl Future<Output=Result<(), WorkerCommError>>, WorkerCommError>
pub async fn send_command(&mut self, command: CommandKind) -> Result<impl Future<Output=Result<Response, WorkerCommError>>, WorkerCommError>
{
let (tx, rx) = oneshot::channel();
self.chan.send(Command(command, tx)).await.map_err(|_| WorkerCommError)?;
@ -157,7 +162,7 @@ impl<B: ProgressBar> Handle<B>
}
/// Send a command to the worker and then wait for it to be processed
pub async fn send_command_and_wait(&mut self, command: CommandKind) -> Result<(), WorkerCommError>
pub async fn send_command_and_wait(&mut self, command: CommandKind) -> Result<Response, WorkerCommError>
{
self.send_command(command).await?.await
}
@ -241,7 +246,35 @@ pub fn host<B: ProgressBar + Send + Sync + 'static>(bar: B) -> (Handle<B>, JoinH
() => {};
}
while let Some(Command(command, response)) = rx.recv().await {
let _response = util::defer(move || response.send(()).ignore());
let response = Arc::new(std::sync::Mutex::new(Some(response)));
/// Send a response if one has not already been sent.
///
/// # Returns
/// * `Some(Ok(())` - if response was sent okay
/// * `Some(Err(_))` - if response failed to send.
/// * `None` - if response has already been sent
///
/// # Panics
/// If mutex is poisoned (this should be impossible).
macro_rules! send_response {
($value:expr) => (send_response!(@ response => Some(Box::new($value))));
(@ $response:ident => $value:expr) => {
{
if let Some(response) = $response.lock().unwrap().take() {
Some(response.send($value))
} else {
None
}
}
};
}
// Guard that ensures a `None` response is sent after this command has been processed, if an explicit response has not yet been sent.
let _resp = {
let response = Arc::clone(&response);
util::defer(move || send_response!(@ response => None).ignore())
};
match command {
CommandKind::Shutdown => break,
CommandKind::BumpHigh(sz) if sz >= 0 => {
@ -272,6 +305,8 @@ pub fn host<B: ProgressBar + Send + Sync + 'static>(bar: B) -> (Handle<B>, JoinH
},
CommandKind::Line(line) => update_bar!(write line),
CommandKind::LineErr(line) => update_bar!(write error line),
//TODO: Title
CommandKind::Many(_) => unimplemented!(),
}
}

@ -0,0 +1,140 @@
//! Tasklist for progressbar
use super::*;
use std::{
collections::LinkedList,
fmt,
error,
};
use uuid::Uuid;
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct TaskId(Uuid);
impl fmt::Display for TaskId
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "<{}>", self.0)
}
}
/// A list of tasks
#[derive(Debug, Clone)]
pub struct TaskList
{
tasks: LinkedList<(Uuid, String)>,
strbuf: String,
}
impl fmt::Display for TaskList
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.strbuf)
}
}
impl TaskList
{
/// The current full string
pub fn as_str(&self) -> &str
{
self.strbuf.as_str()
}
/// Create a new, empty tasklist
pub fn new() -> Self
{
Self{tasks:LinkedList::new(), strbuf:String::new()}
}
fn recalc_buf(&mut self)
{
self.strbuf = self.tasks.iter().map(|(_, stri)| stri.as_str()).join(", ");
}
fn push_buf_one(&mut self, task: &str)
{
if self.strbuf.len() > 0 {
self.strbuf.push_str(", ");
}
self.strbuf.push_str(task)
}
/// Add a task to the end of the list
pub fn add(&mut self, task: String) -> TaskId
{
let id = Uuid::new_v4();
self.push_buf_one(&task[..]);
self.tasks.push_back((id.clone(), task));
TaskId(id)
}
/// Remove all tasks
pub fn clear(&mut self)
{
self.tasks.clear();
self.strbuf.clear();
}
/// An iterator over all tasks currently in
pub fn tasks(&self) -> impl Iterator<Item = &'_ str> + '_
{
self.tasks.iter().map(|(_, strs)| strs.as_str())
}
/// Remove this task from the list, returning its string if it exists
pub fn remove(&mut self, task_id: &TaskId) -> Result<String, IdNotFoundError>
{
let value = match self.tasks.drain_filter(|(id, _)| id==&task_id.0).next() {
Some((_, string)) => string,
None => return Err(IdNotFoundError(TaskId(task_id.0.clone()))),
};
self.recalc_buf();
Ok(value)
}
/// Get this task ID's string
pub fn task_get(&self, task_id: &TaskId)-> Option<&str>
{
self.tasks.iter().filter(|(id, _)| id == &task_id.0).next().map(|x| x.1.as_str())
}
/// Replace this task ID with this string, retuning the old one.
pub fn task_set(&mut self, task_id: &TaskId, value: impl Into<String>) -> Result<String, IdNotFoundError>
{
let old = match self.tasks.iter_mut().filter(|(id, _)| id == &task_id.0).next().map(|x| &mut x.1) {
Some(string) => std::mem::replace(string, value.into()),
None => return Err(IdNotFoundError(TaskId(task_id.0.clone()))),
};
self.recalc_buf();
Ok(old)
}
}
/// Error when trying to remove a non-existent ID.
#[derive(Debug)]
pub struct IdNotFoundError(TaskId);
impl IdNotFoundError
{
/// Get the ID that was not found
pub fn id(&self) -> &TaskId
{
&self.0
}
}
impl error::Error for IdNotFoundError{}
impl fmt::Display for IdNotFoundError
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}: unknown ID to this TaskList", self.0)
}
}
Loading…
Cancel
Save