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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum TransportMode {
10 Bare,
11 Stable,
12}
13
14/// Marker trait that requires [`Send`] on native targets, nothing on wasm32.
15#[cfg(not(target_arch = "wasm32"))]
16pub trait MaybeSend: Send {}
17#[cfg(not(target_arch = "wasm32"))]
18impl<T: Send> MaybeSend for T {}
19
20#[cfg(target_arch = "wasm32")]
21pub trait MaybeSend {}
22#[cfg(target_arch = "wasm32")]
23impl<T> MaybeSend for T {}
24
25/// Marker trait that requires [`Sync`] on native targets, nothing on wasm32.
26#[cfg(not(target_arch = "wasm32"))]
27pub trait MaybeSync: Sync {}
28#[cfg(not(target_arch = "wasm32"))]
29impl<T: Sync> MaybeSync for T {}
30
31#[cfg(target_arch = "wasm32")]
32pub trait MaybeSync {}
33#[cfg(target_arch = "wasm32")]
34impl<T> MaybeSync for T {}
35
36/// A future that is `Send` on native targets, nothing on wasm32.
37/// Unlike `MaybeSend`, this can be used as `dyn MaybeSendFuture` because
38/// it's a single trait (not `dyn Future + MaybeSend`).
39#[cfg(not(target_arch = "wasm32"))]
40pub trait MaybeSendFuture: Future + Send {}
41#[cfg(not(target_arch = "wasm32"))]
42impl<T: Future + Send> MaybeSendFuture for T {}
43
44#[cfg(target_arch = "wasm32")]
45pub trait MaybeSendFuture: Future {}
46#[cfg(target_arch = "wasm32")]
47impl<T: Future> MaybeSendFuture for T {}
48
49/// Bidirectional raw-bytes transport.
50///
51/// TCP, WebSocket, SHM all implement this. No knowledge of what's being
52/// sent — just bytes in, bytes out. The transport provides write buffers
53/// so callers can encode directly into the destination (zero-copy for SHM).
54// r[impl link]
55// r[impl link.message]
56// r[impl link.order]
57pub trait Link {
58 type Tx: LinkTx;
59 type Rx: LinkRx;
60
61 // r[impl link.split]
62 fn split(self) -> (Self::Tx, Self::Rx);
63
64 /// Whether this link supports the requested transport mode.
65 ///
66 /// Most links support both `bare` and `stable`. Special transports may
67 /// override this to reject unsupported modes during the transport
68 /// prologue.
69 fn supports_transport_mode(mode: TransportMode) -> bool
70 where
71 Self: Sized,
72 {
73 let _ = mode;
74 true
75 }
76}
77
78/// Sending half of a [`Link`].
79///
80/// Callers provide an owned payload buffer; the transport applies any framing
81/// and enqueues or writes it asynchronously. Backpressure lives in [`LinkTx::send`].
82pub trait LinkTx: MaybeSend + MaybeSync + 'static {
83 /// Send one payload.
84 ///
85 /// The `Vec<u8>` is caller-owned until the transport accepts it into its
86 /// internal queue or write path.
87 fn send(&self, bytes: Vec<u8>) -> impl Future<Output = std::io::Result<()>> + MaybeSend + '_;
88
89 /// Graceful close of the outbound direction.
90 // r[impl link.tx.close]
91 fn close(self) -> impl Future<Output = std::io::Result<()>> + MaybeSend
92 where
93 Self: Sized;
94}
95
96/// Receiving half of a [`Link`].
97///
98/// Yields [`Backing`] values: the raw bytes plus their ownership handle.
99/// The transport handles framing (length-prefix, WebSocket frames, etc.)
100/// and returns exactly one message's bytes per `recv` call.
101///
102/// For SHM: the Backing might be a VarSlot reference.
103/// For TCP: the Backing is a heap-allocated buffer.
104pub trait LinkRx: MaybeSend + 'static {
105 type Error: std::error::Error + MaybeSend + MaybeSync + 'static;
106
107 /// Receive the next message's raw bytes.
108 ///
109 /// Returns `Ok(None)` when the peer has closed the connection.
110 // r[impl link.rx.recv]
111 // r[impl link.rx.error]
112 // r[impl link.rx.eof]
113 fn recv(
114 &mut self,
115 ) -> impl Future<Output = Result<Option<Backing>, Self::Error>> + MaybeSend + '_;
116}
117
118/// A [`Link`] assembled from pre-split Tx and Rx halves.
119pub struct SplitLink<Tx, Rx> {
120 pub tx: Tx,
121 pub rx: Rx,
122}
123
124impl<Tx: LinkTx, Rx: LinkRx> Link for SplitLink<Tx, Rx> {
125 type Tx = Tx;
126 type Rx = Rx;
127
128 fn split(self) -> (Tx, Rx) {
129 (self.tx, self.rx)
130 }
131}