From bb21b6fd7b4b028f38eaa66b6e073137a52e3a30 Mon Sep 17 00:00:00 2001
From: Yaroslav Dynnikov <yaroslav.dynnikov@gmail.com>
Date: Fri, 23 Sep 2022 21:04:28 +0300
Subject: [PATCH] doc: mailbox

---
 src/mailbox.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/src/mailbox.rs b/src/mailbox.rs
index 1648e7fc3e..dadeafaeed 100644
--- a/src/mailbox.rs
+++ b/src/mailbox.rs
@@ -1,3 +1,10 @@
+//! 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);
-- 
GitLab