Skip to main content

nuclei/sync/
mesh.rs

1//! A full mesh of bounded channels between a fixed number of parties.
2//!
3//! [`mesh`] builds, for every ordered pair `(from, to)` of parties, one
4//! [`mpsc::channel`] of the given capacity, and hands each party its ends: a
5//! [`Party`] keeps the sender to every party at the index of that party, and
6//! the receiver from every party at the index of that party. Parties are
7//! numbered `0..parties`. Self-loops are included: party `i` can send to
8//! itself, so "send to the owner of key `k`" needs no special case.
9//!
10//! The mesh only builds channels. Nothing here spawns anything or knows about
11//! workers: moving each [`Party`] into its own task or thread (a `Party` is
12//! `Send` when `T` is) is the caller's, with any `spawn`.
13//!
14//! Backpressure is per pair: a send to a party whose channel from this one is
15//! full waits for that party to take a value, and does not hold up sends to
16//! other parties or from other parties.
17//!
18//! [`Party::recv`] receives from any party and is fair: it polls the
19//! receivers round robin, starting after the one that delivered last, so a
20//! party that floods cannot starve a quiet one. A party's own sender to itself
21//! keeps its self-loop open, so `recv` ends only after
22//! [`Party::close_senders`] too, once every other party dropped its senders and
23//! everything sent was received.
24//!
25//! ```
26//! use nuclei::sync::mesh::mesh;
27//!
28//! nuclei::runtime::block_on(async {
29//!     let mut parties = mesh::<u32>(2, 4);
30//!     let mut b = parties.pop().unwrap();
31//!     let a = parties.pop().unwrap();
32//!     a.send_to(1, 7).await.unwrap();
33//!     assert_eq!(b.recv().await, Some((0, 7)));
34//! });
35//! ```
36
37use core::fmt;
38use core::future::poll_fn;
39use core::task::{Context, Poll};
40
41use crate::sync::mpsc::{
42    self,
43    error::{SendError, TryRecvError, TrySendError},
44};
45
46/// Builds a full mesh of `parties` parties, each pair joined by a bounded
47/// channel of `capacity` messages in each direction. Entry `i` of the answer
48/// is party `i`.
49///
50/// # Panics
51///
52/// When `capacity` is zero, as [`mpsc::channel`] does.
53///
54/// ```
55/// let parties = nuclei::sync::mesh::mesh::<u8>(3, 1);
56/// assert_eq!(parties.len(), 3);
57/// assert_eq!(parties[2].index(), 2);
58/// assert_eq!(parties[2].parties(), 3);
59/// ```
60#[track_caller]
61pub fn mesh<T: Send>(parties: usize, capacity: usize) -> Vec<Party<T>> {
62    assert!(capacity > 0, "mpsc bounded channel requires buffer > 0");
63    let mut senders: Vec<Vec<mpsc::Sender<T>>> =
64        (0..parties).map(|_| Vec::with_capacity(parties)).collect();
65    let mut receivers: Vec<Vec<mpsc::Receiver<T>>> =
66        (0..parties).map(|_| Vec::with_capacity(parties)).collect();
67    for sending in &mut senders {
68        for receiving in &mut receivers {
69            let (tx, rx) = mpsc::channel(capacity);
70            sending.push(tx);
71            receiving.push(rx);
72        }
73    }
74    senders
75        .into_iter()
76        .zip(receivers)
77        .enumerate()
78        .map(|(index, (senders, receivers))| Party {
79            index,
80            parties,
81            ended: vec![false; receivers.len()],
82            ended_count: 0,
83            next: 0,
84            senders,
85            receivers,
86        })
87        .collect()
88}
89
90/// One party of a [`mesh`]: its senders to every party and its receivers from
91/// every party, both indexed by the peer.
92pub struct Party<T> {
93    index: usize,
94    parties: usize,
95    senders: Vec<mpsc::Sender<T>>,
96    receivers: Vec<mpsc::Receiver<T>>,
97    ended: Vec<bool>,
98    ended_count: usize,
99    next: usize,
100}
101
102impl<T> Party<T> {
103    /// This party's index in the mesh.
104    pub fn index(&self) -> usize {
105        self.index
106    }
107
108    /// How many parties the mesh has, this one included.
109    pub fn parties(&self) -> usize {
110        self.parties
111    }
112
113    /// The sender to party `to`, or `None` when `to` is not a party (or the
114    /// senders were closed with [`close_senders`](Self::close_senders)).
115    pub fn sender(&self, to: usize) -> Option<&mpsc::Sender<T>> {
116        self.senders.get(to)
117    }
118
119    /// The receiver from party `from`, or `None` when `from` is not a party.
120    pub fn receiver(&mut self, from: usize) -> Option<&mut mpsc::Receiver<T>> {
121        self.receivers.get_mut(from)
122    }
123
124    /// Sends `value` to party `to`, waiting for room in the channel to it.
125    ///
126    /// # Errors
127    ///
128    /// A [`SendError`] holding the value when `to` is not a party or its
129    /// receiver is gone.
130    pub async fn send_to(&self, to: usize, value: T) -> Result<(), SendError<T>> {
131        match self.senders.get(to) {
132            Some(sender) => sender.send(value).await,
133            None => Err(SendError(value)),
134        }
135    }
136
137    /// Sends `value` to party `to` at once, or says why it cannot be sent.
138    ///
139    /// # Errors
140    ///
141    /// [`TrySendError::Full`] when the channel to `to` is full;
142    /// [`TrySendError::Closed`] when `to` is not a party or its receiver is
143    /// gone. Both hold the value back.
144    pub fn try_send_to(&self, to: usize, value: T) -> Result<(), TrySendError<T>> {
145        match self.senders.get(to) {
146            Some(sender) => sender.try_send(value),
147            None => Err(TrySendError::Closed(value)),
148        }
149    }
150
151    /// Drops every sender of this party, itself included (the self-loop). The
152    /// party then only receives; its sends fail with their value. This is how
153    /// a party lets [`recv`](Self::recv) end.
154    pub fn close_senders(&mut self) {
155        self.senders.clear();
156    }
157
158    /// Receives the next value from party `from`. Answers `None` when `from`
159    /// is not a party, or that channel ended and was drained.
160    pub async fn recv_from(&mut self, from: usize) -> Option<T> {
161        match self.receivers.get_mut(from) {
162            Some(receiver) => receiver.recv().await,
163            None => None,
164        }
165    }
166
167    /// Receives the next value from any party, with the index of the party
168    /// that sent it. Answers `None` once every channel into this party ended
169    /// and was drained.
170    ///
171    /// Cancel safe: a dropped future loses no value.
172    pub async fn recv(&mut self) -> Option<(usize, T)> {
173        poll_fn(|cx| self.poll_recv(cx)).await
174    }
175
176    /// Polls for a value from any party. The receivers are polled round
177    /// robin from the one after the last that delivered, so no party is
178    /// starved, and each one that has nothing registers the waker of `cx`.
179    pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<(usize, T)>> {
180        let n = self.receivers.len();
181        for step in 0..n {
182            let from = (self.next + step) % n;
183            if self.ended[from] {
184                continue;
185            }
186            match self.receivers[from].poll_recv(cx) {
187                Poll::Ready(Some(value)) => {
188                    self.next = (from + 1) % n;
189                    return Poll::Ready(Some((from, value)));
190                }
191                Poll::Ready(None) => self.end(from),
192                Poll::Pending => {}
193            }
194        }
195        if self.ended_count == n {
196            Poll::Ready(None)
197        } else {
198            Poll::Pending
199        }
200    }
201
202    /// Receives a value from any party without waiting, in the order
203    /// [`poll_recv`](Self::poll_recv) uses.
204    ///
205    /// # Errors
206    ///
207    /// [`TryRecvError::Empty`] when nothing is waiting and a value may yet
208    /// come; [`TryRecvError::Disconnected`] only when every channel ended and
209    /// was drained.
210    pub fn try_recv(&mut self) -> Result<(usize, T), TryRecvError> {
211        let n = self.receivers.len();
212        for step in 0..n {
213            let from = (self.next + step) % n;
214            if self.ended[from] {
215                continue;
216            }
217            match self.receivers[from].try_recv() {
218                Ok(value) => {
219                    self.next = (from + 1) % n;
220                    return Ok((from, value));
221                }
222                Err(TryRecvError::Disconnected) => self.end(from),
223                Err(TryRecvError::Empty) => {}
224            }
225        }
226        if self.ended_count == n {
227            Err(TryRecvError::Disconnected)
228        } else {
229            Err(TryRecvError::Empty)
230        }
231    }
232
233    fn end(&mut self, from: usize) {
234        self.ended[from] = true;
235        self.ended_count += 1;
236    }
237
238    /// Takes the party apart: its senders and its receivers, indexed by peer.
239    pub fn into_parts(self) -> (Vec<mpsc::Sender<T>>, Vec<mpsc::Receiver<T>>) {
240        (self.senders, self.receivers)
241    }
242}
243
244impl<T> fmt::Debug for Party<T> {
245    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246        f.debug_struct("Party")
247            .field("index", &self.index)
248            .field("parties", &self.parties)
249            .finish()
250    }
251}