* refactor(fakes): clean up add_terminal_input * refactor(fakes): append whole buf to output_buffer in FakeStdoutWriter::write * refactor(fakes): append whole buf to output_buffer in FakeInputOutput::write_to_tty_stdin * fix(fakes): allow partial reads in read_from_tty_stdout This patch fixes two bugs in read_from_tty_stdout: * if there was a partial read (ie. `bytes.read_position` is not 0 but less than `bytes.content.len()`), subsequent calls to would fill `buf` starting at index `bytes.read_position` instead of 0, leaving range 0..`bytes.read_position` untouched. * if `buf` was smaller than `bytes.content.len()`, a panic would occur. * refactor(channels): use crossbeam instead of mpsc This patch replaces mpsc with crossbeam channels because crossbeam supports selecting on multiple channels which will be necessary in a subsequent patch. * refactor(threadbus): allow multiple receivers in Bus This patch changes Bus to use multiple receivers. Method `recv` returns data from all of them. This will be used in a subsequent patch for receiving from bounded and unbounded queues at the same time. * refactor(channels): remove SenderType enum This enum has only one variant, so the entire enum can be replaced with the innards of said variant. * refactor(channels): remove Send+Sync trait implementations The implementation of these traits is not necessary, as SenderWithContext is automatically Send and Sync for every T and ErrorContext that's Send and Sync.
42 lines
1.5 KiB
Rust
42 lines
1.5 KiB
Rust
//! Definitions and helpers for sending and receiving messages between threads.
|
|
|
|
use async_std::task_local;
|
|
use std::cell::RefCell;
|
|
|
|
use crate::errors::{get_current_ctx, ErrorContext};
|
|
pub use crossbeam::channel::{bounded, unbounded, Receiver, RecvError, Select, SendError, Sender};
|
|
|
|
/// An [MPSC](mpsc) asynchronous channel with added error context.
|
|
pub type ChannelWithContext<T> = (Sender<(T, ErrorContext)>, Receiver<(T, ErrorContext)>);
|
|
|
|
/// Sends messages on an [MPSC](std::sync::mpsc) channel, along with an [`ErrorContext`],
|
|
/// synchronously or asynchronously depending on the underlying [`SenderType`].
|
|
#[derive(Clone)]
|
|
pub struct SenderWithContext<T> {
|
|
sender: Sender<(T, ErrorContext)>,
|
|
}
|
|
|
|
impl<T: Clone> SenderWithContext<T> {
|
|
pub fn new(sender: Sender<(T, ErrorContext)>) -> Self {
|
|
Self { sender }
|
|
}
|
|
|
|
/// Sends an event, along with the current [`ErrorContext`], on this
|
|
/// [`SenderWithContext`]'s channel.
|
|
pub fn send(&self, event: T) -> Result<(), SendError<(T, ErrorContext)>> {
|
|
let err_ctx = get_current_ctx();
|
|
self.sender.send((event, err_ctx))
|
|
}
|
|
}
|
|
|
|
thread_local!(
|
|
/// A key to some thread local storage (TLS) that holds a representation of the thread's call
|
|
/// stack in the form of an [`ErrorContext`].
|
|
pub static OPENCALLS: RefCell<ErrorContext> = RefCell::default()
|
|
);
|
|
|
|
task_local! {
|
|
/// A key to some task local storage that holds a representation of the task's call
|
|
/// stack in the form of an [`ErrorContext`].
|
|
pub static ASYNCOPENCALLS: RefCell<ErrorContext> = RefCell::default()
|
|
}
|