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/// Marker trait that requires [`Send`] on native targets, nothing on wasm32.
8#[cfg(not(target_arch = "wasm32"))]
9pub trait MaybeSend: Send {}
10#[cfg(not(target_arch = "wasm32"))]
11impl<T: Send> MaybeSend for T {}
12
13#[cfg(target_arch = "wasm32")]
14pub trait MaybeSend {}
15#[cfg(target_arch = "wasm32")]
16impl<T> MaybeSend for T {}
17
18/// Marker trait that requires [`Sync`] on native targets, nothing on wasm32.
19#[cfg(not(target_arch = "wasm32"))]
20pub trait MaybeSync: Sync {}
21#[cfg(not(target_arch = "wasm32"))]
22impl<T: Sync> MaybeSync for T {}
23
24#[cfg(target_arch = "wasm32")]
25pub trait MaybeSync {}
26#[cfg(target_arch = "wasm32")]
27impl<T> MaybeSync for T {}
28
29/// A future that is `Send` on native targets, nothing on wasm32.
30/// Unlike `MaybeSend`, this can be used as `dyn MaybeSendFuture` because
31/// it's a single trait (not `dyn Future + MaybeSend`).
32#[cfg(not(target_arch = "wasm32"))]
33pub trait MaybeSendFuture: Future + Send {}
34#[cfg(not(target_arch = "wasm32"))]
35impl<T: Future + Send> MaybeSendFuture for T {}
36
37#[cfg(target_arch = "wasm32")]
38pub trait MaybeSendFuture: Future {}
39#[cfg(target_arch = "wasm32")]
40impl<T: Future> MaybeSendFuture for T {}
41
42/// Bidirectional raw-bytes transport.
43///
44/// TCP, WebSocket, local IPC, and in-memory transports implement this. No
45/// knowledge of what's being sent — just bytes in, bytes out.
46// r[impl link]
47// r[impl link.message]
48// r[impl link.order]
49pub trait Link {
50    type Tx: LinkTx;
51    type Rx: LinkRx;
52
53    // r[impl link.split]
54    fn split(self) -> (Self::Tx, Self::Rx);
55}
56
57/// Sending half of a [`Link`].
58///
59/// Callers provide an owned payload buffer; the transport applies any framing
60/// and enqueues or writes it asynchronously. Backpressure lives in [`LinkTx::send`].
61pub trait LinkTx: MaybeSend + MaybeSync + 'static {
62    /// Send one payload.
63    ///
64    /// The `Vec<u8>` is caller-owned until the transport accepts it into its
65    /// internal queue or write path.
66    fn send(&self, bytes: Vec<u8>) -> impl Future<Output = std::io::Result<()>> + MaybeSend + '_;
67
68    /// Graceful close of the outbound direction.
69    // r[impl link.tx.close]
70    fn close(self) -> impl Future<Output = std::io::Result<()>> + MaybeSend
71    where
72        Self: Sized;
73
74    /// Whether this transport can carry file descriptors (`SCM_RIGHTS` over a
75    /// Unix-domain socket). Only such links may carry [`Fd`](crate::fd::Fd)
76    /// values; everything else (TCP, WebSocket, wasm) returns `false` and the
77    /// encoder refuses fd-bearing messages.
78    fn supports_fd_passing(&self) -> bool {
79        false
80    }
81
82    /// Send one payload that carries `fds` out-of-band via `SCM_RIGHTS`.
83    ///
84    /// The default errors if any fds are present (a transport that cannot
85    /// pass descriptors must never be handed one); with no fds it is exactly
86    /// [`send`](Self::send), so existing transports need no change. Off-Unix
87    /// [`FrameFds`](crate::FrameFds) is `()` and this is always plain
88    /// [`send`](Self::send).
89    fn send_with_fds(
90        &self,
91        bytes: Vec<u8>,
92        fds: crate::FrameFds,
93    ) -> impl Future<Output = std::io::Result<()>> + MaybeSend + '_ {
94        async move {
95            #[cfg(unix)]
96            if !fds.is_empty() {
97                return Err(std::io::Error::other(
98                    "transport does not support fd passing",
99                ));
100            }
101            let _ = &fds;
102            self.send(bytes).await
103        }
104    }
105}
106
107/// Receiving half of a [`Link`].
108///
109/// Yields [`Backing`] values: the raw bytes plus their ownership handle.
110/// The transport handles framing (length-prefix, WebSocket frames, etc.)
111/// and returns exactly one message's bytes per `recv` call.
112///
113/// For current transports, the backing is usually a heap-allocated buffer.
114pub trait LinkRx: MaybeSend + 'static {
115    type Error: std::error::Error + MaybeSend + MaybeSync + 'static;
116
117    /// Receive the next message's raw bytes.
118    ///
119    /// Returns `Ok(None)` when the peer has closed the connection.
120    // r[impl link.rx.recv]
121    // r[impl link.rx.error]
122    // r[impl link.rx.eof]
123    fn recv(
124        &mut self,
125    ) -> impl Future<Output = Result<Option<Backing>, Self::Error>> + MaybeSend + '_;
126
127    /// Take the file descriptors that arrived with the frame returned by the
128    /// most recent [`recv`](Self::recv).
129    ///
130    /// Descriptors travel out-of-band in `SCM_RIGHTS`; an fd-capable link
131    /// attributes each batch to the frame whose bytes completed it (one
132    /// fd-bearing frame == one `sendmsg`). The default returns none, so
133    /// non-fd transports need no change. The conduit threads these to the
134    /// typed-decode site as the [`provide_fds`](crate::provide_fds) source.
135    fn take_frame_fds(&mut self) -> crate::FrameFds {
136        crate::FrameFds::default()
137    }
138}
139
140/// A [`Link`] assembled from pre-split Tx and Rx halves.
141pub struct SplitLink<Tx, Rx> {
142    pub tx: Tx,
143    pub rx: Rx,
144}
145
146impl<Tx: LinkTx, Rx: LinkRx> Link for SplitLink<Tx, Rx> {
147    type Tx = Tx;
148    type Rx = Rx;
149
150    fn split(self) -> (Tx, Rx) {
151        (self.tx, self.rx)
152    }
153}