dialectic/
backend.rs

1//! The interface implemented by all transport backends for a [`Chan`](crate::Chan).
2//!
3//! A [`Chan<S, Tx, Rx>`](crate::Chan) is parameterized by its transmitting channel `Tx` and its
4//! receiving channel `Rx`. In order to use a `Chan` to run a session, these underlying channels
5//! must implement the traits [`Transmitter`] and [`Receiver`], as well as [`Transmit<T>`](Transmit)
6//! and [`Receive<T>`](Receive) for at least the types `T` used in those capacities in any given
7//! session.
8//!
9//! Functions which are generic over their backend will in turn need to specify the bounds
10//! [`Transmit<T>`](Transmit) and [`Receive<T>`](Receive) for all `T`s they send and receive,
11//! respectively. The [`Transmitter`](macro@crate::Transmitter) and
12//! [`Receiver`](macro@crate::Receiver) attribute macros make this bound specification succinct; see
13//! their documentation for more details.
14
15#[doc(no_inline)]
16pub use call_by::{By, Convention, Mut, Ref, Val};
17use std::{future::Future, pin::Pin};
18
19mod choice;
20pub use choice::*;
21
22/// A backend transport used for transmitting (i.e. the `Tx` parameter of [`Chan`](crate::Chan))
23/// must implement [`Transmitter`], which specifies what type of errors it might return, as well as
24/// giving a method to send [`Choice`]s across the channel. This is a super-trait of [`Transmit`],
25/// which is what's actually needed to receive particular values over a [`Chan`](crate::Chan).
26///
27/// If you're writing a function and need a lot of different [`Transmit<T>`](Transmit) bounds, the
28/// [`Transmitter`](macro@crate::Transmitter) attribute macro can help you specify them more
29/// succinctly.
30pub trait Transmitter {
31    /// The type of possible errors when sending.
32    type Error;
33
34    /// Send any `Choice<N>` using the [`Convention`] specified by the trait implementation.
35    fn send_choice<'async_lifetime, const LENGTH: usize>(
36        &'async_lifetime mut self,
37        choice: Choice<LENGTH>,
38    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_lifetime>>;
39}
40
41/// If a transport is [`Transmit<T, C>`](Transmit), we can use it to [`send`](Transmit::send) a
42/// message of type `T` by [`Val`], [`Ref`], or [`Mut`], depending on the calling convention
43/// specified by `C`.
44///
45/// If you're writing a function and need a lot of different `Transmit<T, C>` bounds, the
46/// [`Transmitter`](macro@crate::Transmitter) attribute macro can help you specify them more
47/// succinctly.
48///
49/// # Examples
50///
51/// For an example of implementing [`Transmit`], check out the source for the implementation of
52/// [`Transmit`] for the [`dialectic_tokio_mpsc::Sender`] type in the [`dialectic_tokio_mpsc`]
53/// crate.
54///
55/// [`dialectic_tokio_mpsc`]: https://docs.rs/dialectic-tokio-mpsc
56///
57/// [`dialectic_tokio_mpsc::Sender`]:
58/// https://docs.rs/dialectic-tokio-mpsc/latest/dialectic_tokio_mpsc/struct.Sender.html
59pub trait Transmit<T, C: Convention = Val>: Transmitter {
60    /// Send a message using the [`Convention`] specified by the trait implementation.
61    fn send<'a, 'async_lifetime>(
62        &'async_lifetime mut self,
63        message: <T as By<'a, C>>::Type,
64    ) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + 'async_lifetime>>
65    where
66        T: By<'a, C>,
67        'a: 'async_lifetime;
68}
69
70/// A backend transport used for receiving (i.e. the `Rx` parameter of [`Chan`](crate::Chan)) must
71/// implement [`Receiver`], which specifies what type of errors it might return, as well as giving a
72/// method to send [`Choice`]s across the channel. This is a super-trait of [`Receive`], which is
73/// what's actually needed to receive particular values over a [`Chan`](crate::Chan).
74///
75/// If you're writing a function and need a lot of different [`Receive<T>`](Receive) bounds, the
76/// [`Receiver`](macro@crate::Receiver) attribute macro can help you specify them more succinctly.
77pub trait Receiver {
78    /// The type of possible errors when receiving.
79    type Error;
80
81    /// Receive any `Choice<N>`. It is impossible to construct a `Choice<0>`, so if `N = 0`, a
82    /// [`Receiver::Error`] must be returned.
83    fn recv_choice<'async_lifetime, const LENGTH: usize>(
84        &'async_lifetime mut self,
85    ) -> Pin<Box<dyn Future<Output = Result<Choice<LENGTH>, Self::Error>> + Send + 'async_lifetime>>;
86}
87
88/// If a transport is [`Receive<T>`](Receive), we can use it to [`recv`](Receive::recv) a message of
89/// type `T`.
90///
91/// If you're writing a function and need a lot of different [`Receive<T>`](Receive) bounds, the
92/// [`Receiver`](macro@crate::Receiver) attribute macro can help you specify them more succinctly.
93///
94/// # Examples
95///
96/// For an example of implementing [`Receive`], check out the source for the implementation of
97/// [`Receive`] for the [`dialectic_tokio_mpsc::Receiver`] type in the [`dialectic_tokio_mpsc`]
98/// crate.
99///
100/// [`dialectic_tokio_mpsc`]: https://docs.rs/dialectic-tokio-mpsc
101///
102/// [`dialectic_tokio_mpsc::Receiver`]:
103/// https://docs.rs/dialectic-tokio-mpsc/latest/dialectic_tokio_mpsc/struct.Receiver.html
104pub trait Receive<T>: Receiver {
105    /// Receive a message. This may require type annotations for disambiguation.
106    fn recv<'async_lifetime>(
107        &'async_lifetime mut self,
108    ) -> Pin<Box<dyn Future<Output = Result<T, Self::Error>> + Send + 'async_lifetime>>;
109}