Skip to main content

vox_types/
link.rs

1#![allow(async_fn_in_trait)]
2
3use std::future::Future;
4
5use crate::Backing;
6
7/// Requested conduit mode for the transport prologue.
8///
9/// Historically this enum had a `Stable` variant for the reconnect /
10/// replay-buffer-backed `StableConduit`; that conduit shape was removed,
11/// leaving only `Bare`. The enum is preserved for now so the wire-level
12/// transport prologue remains backwards-compatible with peers that still
13/// negotiate it; new transports always select `Bare`.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum TransportMode {
16    Bare,
17}
18
19/// Marker trait that requires [`Send`] on native targets, nothing on wasm32.
20#[cfg(not(target_arch = "wasm32"))]
21pub trait MaybeSend: Send {}
22#[cfg(not(target_arch = "wasm32"))]
23impl<T: Send> MaybeSend for T {}
24
25#[cfg(target_arch = "wasm32")]
26pub trait MaybeSend {}
27#[cfg(target_arch = "wasm32")]
28impl<T> MaybeSend for T {}
29
30/// Marker trait that requires [`Sync`] on native targets, nothing on wasm32.
31#[cfg(not(target_arch = "wasm32"))]
32pub trait MaybeSync: Sync {}
33#[cfg(not(target_arch = "wasm32"))]
34impl<T: Sync> MaybeSync for T {}
35
36#[cfg(target_arch = "wasm32")]
37pub trait MaybeSync {}
38#[cfg(target_arch = "wasm32")]
39impl<T> MaybeSync for T {}
40
41/// A future that is `Send` on native targets, nothing on wasm32.
42/// Unlike `MaybeSend`, this can be used as `dyn MaybeSendFuture` because
43/// it's a single trait (not `dyn Future + MaybeSend`).
44#[cfg(not(target_arch = "wasm32"))]
45pub trait MaybeSendFuture: Future + Send {}
46#[cfg(not(target_arch = "wasm32"))]
47impl<T: Future + Send> MaybeSendFuture for T {}
48
49#[cfg(target_arch = "wasm32")]
50pub trait MaybeSendFuture: Future {}
51#[cfg(target_arch = "wasm32")]
52impl<T: Future> MaybeSendFuture for T {}
53
54/// Bidirectional raw-bytes transport.
55///
56/// TCP, WebSocket, SHM all implement this. No knowledge of what's being
57/// sent — just bytes in, bytes out. The transport provides write buffers
58/// so callers can encode directly into the destination (zero-copy for SHM).
59// r[impl link]
60// r[impl link.message]
61// r[impl link.order]
62pub trait Link {
63    type Tx: LinkTx;
64    type Rx: LinkRx;
65
66    // r[impl link.split]
67    fn split(self) -> (Self::Tx, Self::Rx);
68
69    /// Whether this link supports the requested transport mode.
70    ///
71    /// Most links support both `bare` and `stable`. Special transports may
72    /// override this to reject unsupported modes during the transport
73    /// prologue.
74    fn supports_transport_mode(mode: TransportMode) -> bool
75    where
76        Self: Sized,
77    {
78        let _ = mode;
79        true
80    }
81}
82
83/// Sending half of a [`Link`].
84///
85/// Callers provide an owned payload buffer; the transport applies any framing
86/// and enqueues or writes it asynchronously. Backpressure lives in [`LinkTx::send`].
87pub trait LinkTx: MaybeSend + MaybeSync + 'static {
88    /// Send one payload.
89    ///
90    /// The `Vec<u8>` is caller-owned until the transport accepts it into its
91    /// internal queue or write path.
92    fn send(&self, bytes: Vec<u8>) -> impl Future<Output = std::io::Result<()>> + MaybeSend + '_;
93
94    /// Graceful close of the outbound direction.
95    // r[impl link.tx.close]
96    fn close(self) -> impl Future<Output = std::io::Result<()>> + MaybeSend
97    where
98        Self: Sized;
99
100    /// Whether this transport can carry file descriptors (`SCM_RIGHTS` over a
101    /// Unix-domain socket). Only such links may carry [`Fd`](crate::fd::Fd)
102    /// values; everything else (TCP, WebSocket, wasm) returns `false` and the
103    /// encoder refuses fd-bearing messages.
104    fn supports_fd_passing(&self) -> bool {
105        false
106    }
107
108    /// Send one payload that carries `fds` out-of-band via `SCM_RIGHTS`.
109    ///
110    /// The default errors if any fds are present (a transport that cannot
111    /// pass descriptors must never be handed one); with no fds it is exactly
112    /// [`send`](Self::send), so existing transports need no change. Off-Unix
113    /// [`FrameFds`](crate::FrameFds) is `()` and this is always plain
114    /// [`send`](Self::send).
115    fn send_with_fds(
116        &self,
117        bytes: Vec<u8>,
118        fds: crate::FrameFds,
119    ) -> impl Future<Output = std::io::Result<()>> + MaybeSend + '_ {
120        async move {
121            #[cfg(unix)]
122            if !fds.is_empty() {
123                return Err(std::io::Error::other(
124                    "transport does not support fd passing",
125                ));
126            }
127            let _ = &fds;
128            self.send(bytes).await
129        }
130    }
131}
132
133/// Receiving half of a [`Link`].
134///
135/// Yields [`Backing`] values: the raw bytes plus their ownership handle.
136/// The transport handles framing (length-prefix, WebSocket frames, etc.)
137/// and returns exactly one message's bytes per `recv` call.
138///
139/// For SHM: the Backing might be a VarSlot reference.
140/// For TCP: the Backing is a heap-allocated buffer.
141pub trait LinkRx: MaybeSend + 'static {
142    type Error: std::error::Error + MaybeSend + MaybeSync + 'static;
143
144    /// Receive the next message's raw bytes.
145    ///
146    /// Returns `Ok(None)` when the peer has closed the connection.
147    // r[impl link.rx.recv]
148    // r[impl link.rx.error]
149    // r[impl link.rx.eof]
150    fn recv(
151        &mut self,
152    ) -> impl Future<Output = Result<Option<Backing>, Self::Error>> + MaybeSend + '_;
153
154    /// Take the file descriptors that arrived with the frame returned by the
155    /// most recent [`recv`](Self::recv).
156    ///
157    /// Descriptors travel out-of-band in `SCM_RIGHTS`; an fd-capable link
158    /// attributes each batch to the frame whose bytes completed it (one
159    /// fd-bearing frame == one `sendmsg`). The default returns none, so
160    /// non-fd transports need no change. The conduit threads these to the
161    /// typed-decode site as the [`provide_fds`](crate::provide_fds) source.
162    fn take_frame_fds(&mut self) -> crate::FrameFds {
163        crate::FrameFds::default()
164    }
165}
166
167/// A [`Link`] assembled from pre-split Tx and Rx halves.
168pub struct SplitLink<Tx, Rx> {
169    pub tx: Tx,
170    pub rx: Rx,
171}
172
173impl<Tx: LinkTx, Rx: LinkRx> Link for SplitLink<Tx, Rx> {
174    type Tx = Tx;
175    type Rx = Rx;
176
177    fn split(self) -> (Tx, Rx) {
178        (self.tx, self.rx)
179    }
180}