quic_rpc/transport/
mod.rs

1//! Built in transports for quic-rpc
2//!
3//! There are two sides to a transport, a server side where connections are
4//! accepted and a client side where connections are initiated.
5//!
6//! Connections are bidirectional typed channels, with a distinct type for
7//! the send and receive side. They are *unrelated* to services.
8//!
9//! In the transport module, the message types are referred to as `In` and `Out`.
10//!
11//! A [`Connector`] can be used to *open* bidirectional typed channels using
12//! [`Connector::open`]. A [`Listener`] can be used to *accept* bidirectional
13//! typed channels from any of the currently opened connections to clients, using
14//! [`Listener::accept`].
15//!
16//! In both cases, the result is a tuple of a send side and a receive side. These
17//! types are defined by implementing the [`StreamTypes`] trait.
18//!
19//! Errors for both sides are defined by implementing the [`ConnectionErrors`] trait.
20use std::{
21    fmt::{self, Debug, Display},
22    net::SocketAddr,
23};
24
25use boxed::{BoxableConnector, BoxableListener, BoxedConnector, BoxedListener};
26use futures_lite::{Future, Stream};
27use futures_sink::Sink;
28use mapped::MappedConnector;
29
30use crate::{RpcError, RpcMessage};
31
32pub mod boxed;
33pub mod combined;
34#[cfg(feature = "flume-transport")]
35#[cfg_attr(quicrpc_docsrs, doc(cfg(feature = "flume-transport")))]
36pub mod flume;
37#[cfg(feature = "hyper-transport")]
38#[cfg_attr(quicrpc_docsrs, doc(cfg(feature = "hyper-transport")))]
39pub mod hyper;
40#[cfg(feature = "iroh-transport")]
41#[cfg_attr(quicrpc_docsrs, doc(cfg(feature = "iroh-transport")))]
42pub mod iroh;
43pub mod mapped;
44pub mod misc;
45#[cfg(feature = "quinn-transport")]
46#[cfg_attr(quicrpc_docsrs, doc(cfg(feature = "quinn-transport")))]
47pub mod quinn;
48
49#[cfg(any(feature = "quinn-transport", feature = "iroh-transport"))]
50#[cfg_attr(
51    quicrpc_docsrs,
52    doc(cfg(any(feature = "quinn-transport", feature = "iroh-transport")))
53)]
54mod util;
55
56/// Errors that can happen when creating and using a [`Connector`] or [`Listener`].
57pub trait ConnectionErrors: Debug + Clone + Send + Sync + 'static {
58    /// Error when sending a message via a channel
59    type SendError: RpcError;
60    /// Error when receiving a message via a channel
61    type RecvError: RpcError;
62    /// Error when opening a channel
63    type OpenError: RpcError;
64    /// Error when accepting a channel
65    type AcceptError: RpcError;
66}
67
68/// Types that are common to both [`Connector`] and [`Listener`].
69///
70/// Having this as a separate trait is useful when writing generic code that works with both.
71pub trait StreamTypes: ConnectionErrors {
72    /// The type of messages that can be received on the channel
73    type In: RpcMessage;
74    /// The type of messages that can be sent on the channel
75    type Out: RpcMessage;
76    /// Receive side of a bidirectional typed channel
77    type RecvStream: Stream<Item = Result<Self::In, Self::RecvError>>
78        + Send
79        + Sync
80        + Unpin
81        + 'static;
82    /// Send side of a bidirectional typed channel
83    type SendSink: Sink<Self::Out, Error = Self::SendError> + Send + Sync + Unpin + 'static;
84}
85
86/// A connection to a specific remote machine
87///
88/// A connection can be used to open bidirectional typed channels using [`Connector::open`].
89pub trait Connector: StreamTypes {
90    /// Open a channel to the remote che
91    fn open(
92        &self,
93    ) -> impl Future<Output = Result<(Self::SendSink, Self::RecvStream), Self::OpenError>> + Send;
94
95    /// Map the input and output types of this connection
96    fn map<In1, Out1>(self) -> MappedConnector<In1, Out1, Self>
97    where
98        In1: TryFrom<Self::In>,
99        Self::Out: From<Out1>,
100    {
101        MappedConnector::new(self)
102    }
103
104    /// Box the connection
105    fn boxed(self) -> BoxedConnector<Self::In, Self::Out>
106    where
107        Self: BoxableConnector<Self::In, Self::Out> + Sized + 'static,
108    {
109        self::BoxedConnector::new(self)
110    }
111}
112
113/// A listener that listens for connections
114///
115/// A listener can be used to accept bidirectional typed channels from any of the
116/// currently opened connections to clients, using [`Listener::accept`].
117pub trait Listener: StreamTypes {
118    /// Accept a new typed bidirectional channel on any of the connections we
119    /// have currently opened.
120    fn accept(
121        &self,
122    ) -> impl Future<Output = Result<(Self::SendSink, Self::RecvStream), Self::AcceptError>> + Send;
123
124    /// The local addresses this endpoint is bound to.
125    fn local_addr(&self) -> &[LocalAddr];
126
127    /// Box the listener
128    fn boxed(self) -> BoxedListener<Self::In, Self::Out>
129    where
130        Self: BoxableListener<Self::In, Self::Out> + Sized + 'static,
131    {
132        BoxedListener::new(self)
133    }
134}
135
136/// The kinds of local addresses a [Listener] can be bound to.
137///
138/// Returned by [Listener::local_addr].
139///
140/// [`Display`]: fmt::Display
141#[derive(Debug, Clone)]
142#[non_exhaustive]
143pub enum LocalAddr {
144    /// A local socket.
145    Socket(SocketAddr),
146    /// An in-memory address.
147    Mem,
148}
149
150impl Display for LocalAddr {
151    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152        match self {
153            LocalAddr::Socket(sockaddr) => write!(f, "{sockaddr}"),
154            LocalAddr::Mem => write!(f, "mem"),
155        }
156    }
157}