Skip to content
Snippets Groups Projects
Commit bb21b6fd authored by Yaroslav Dynnikov's avatar Yaroslav Dynnikov
Browse files

doc: mailbox

parent 6379a7e5
No related branches found
No related tags found
1 merge request!263doc: mailbox
Pipeline #12276 passed
//! Another inter-fiber communication primitive.
//!
//! The type [`Mailbox<T>`] is similar to the `tarantool::fiber::Channel<T>`.
//! But unlike channels which are fixed-size, the mailbox holds messages in a
//! growable `Vec<T>`.
//!
use ::tarantool::fiber;
use std::cell::RefCell;
use std::rc::Rc;
......@@ -8,6 +15,45 @@ struct Inner<T> {
content: RefCell<Vec<T>>,
}
/// An inter-fiber communication channel based on `Vec<T>`.
///
/// One can send messages one by one, transferring the ownership.
///
/// ```
/// let mailbox: Mailbox<String> = Mailbox::new();
/// mailbox.send("Hello".into());
/// mailbox.send("World".into());
/// ```
///
/// Messages are delivered in the same order as they're sent.
///
/// Receiving them is possible in two ways:
///
/// 1. Blocking
///
/// ```
/// let mailbox: Mailbox<String> = Mailbox::new();
/// let timeout = Duration::from_secs(1);
///
/// mailbox.send("Hello".into());
/// mailbox.send("World".into());
///
/// // Won't yield as mailbox isn't empty.
/// assert_eq!(mailbox.receive_all(timeout), vec!["Hello", "World"]);
///
/// // Will yield and subsequently timeout.
/// assert_eq!(mailbox.receive_all(timeout), vec![]);
/// ```
///
/// 2. Non-blocking
///
/// ```
/// let mailbox: Mailbox<()> = Mailbox::new();
///
/// // Won't ever yield.
/// assert_eq!(mailbox.try_receive_all(), vec![]);
/// ```
///
pub struct Mailbox<T>(Rc<Inner<T>>);
impl<T> Clone for Mailbox<T> {
......@@ -24,6 +70,7 @@ impl<T> ::std::fmt::Debug for Mailbox<T> {
}
impl<T> Mailbox<T> {
/// Creates a new, empty mailbox.
pub fn new() -> Self {
Self(Rc::new(Inner {
cond: Rc::default(),
......@@ -31,6 +78,8 @@ impl<T> Mailbox<T> {
}))
}
/// Creates an empty mailbox using the provided `fiber::Cond`. This
/// allows sharing the same `cond` in several places.
pub fn with_cond(cond: Rc<fiber::Cond>) -> Self {
Self(Rc::new(Inner {
cond,
......@@ -38,15 +87,58 @@ impl<T> Mailbox<T> {
}))
}
/// Puts `value` into the mailbox and wakes up a pending recipient.
///
/// The mailbox size is unlimited, so sending a message never blocks
/// the calling fiber.
///
pub fn send(&self, v: T) {
self.0.content.borrow_mut().push(v);
self.0.cond.signal();
}
/// Checks the mailbox for incoming messages without blocking the
/// caller.
///
/// Always returns a `Vec<T>`, either empty or not.
///
/// # Examples
/// ```
/// let mailbox: Mailbox<i32> = Mailbox::new();
/// mailbox.send(9);
///
/// assert_eq!(mailbox.try_receive_all(), vec![9]); // doesn't yield
/// assert_eq!(mailbox.try_receive_all(), vec![]); // doesn't yield either
/// ```
pub fn try_receive_all(&self) -> Vec<T> {
self.0.content.take()
}
/// Checks the mailbox for incoming messages. If there're none, puts
/// the calling fiber into sleep and yields. The fiber is resumed in
/// any of these events:
///
/// - Some other fiber sends a message using [`Self::send`].
/// - Some other fiber signals a `cond` provided in
/// [`Self::with_cond`].
/// - Upon expiration of the `timeout`.
///
/// # Yields
///
/// This function will yield if the mailbox is empty. Even if
/// `timeout` is zero. It won't yield if there're some messages.
///
/// # Examples
///
/// ```
/// let mailbox: Mailbox<i32> = Mailbox::new();
/// let timeout = Duration::from_secs(1);
///
/// mailbox.send(7);
/// assert_eq!(mailbox.receive_all(timeout), vec![7]); // doesn't yield
/// assert_eq!(mailbox.receive_all(timeout), vec![]); // yields until timeout expires
/// ```
///
pub fn receive_all(&self, timeout: Duration) -> Vec<T> {
if self.0.content.borrow().is_empty() {
self.0.cond.wait_timeout(timeout);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment