Skip to main content

dope_net/wire/
mod.rs

1pub mod buffered;
2pub mod identity;
3pub mod reservation;
4pub mod send;
5
6use std::io;
7
8use dope_core::driver::DriverRef;
9use dope_core::driver::ready::ReadyKey;
10use dope_core::driver::token::Token;
11use o3::buffer::{Borrowed, Retained};
12
13use self::send::{Plain, Prepared, SendStorage, Sent, Storage, Vectored};
14pub use dope_core::io::recv::{Lease, View};
15
16use crate::{Bytes, RetainBytes};
17
18pub enum Reclaim {
19    OnSubmit,
20    OnComplete,
21}
22
23pub enum RecvChunk<'a, R> {
24    /// A transformed range that aliases the current provided receive buffer.
25    Borrowed(Bytes<Borrowed<'a>>),
26    /// Wire-owned output independent of the current provided receive buffer.
27    Owned(R),
28}
29
30/// A checked writer over uninitialized receive storage.
31///
32/// Its initialized length can only advance through methods that write every
33/// byte in the committed prefix.
34pub struct RecvTarget<'a> {
35    buffer: &'a mut Vec<u8>,
36    limit: usize,
37}
38
39impl<'a> RecvTarget<'a> {
40    pub fn new(buffer: &'a mut Vec<u8>) -> Self {
41        buffer.clear();
42        let limit = buffer.capacity();
43        Self { buffer, limit }
44    }
45
46    pub fn len(&self) -> usize {
47        self.buffer.len()
48    }
49
50    pub fn is_empty(&self) -> bool {
51        self.buffer.is_empty()
52    }
53
54    pub fn remaining(&self) -> usize {
55        self.limit - self.buffer.len()
56    }
57
58    pub fn write_prefix(&mut self, source: &[u8]) -> usize {
59        let amount = source.len().min(self.remaining());
60        self.buffer.extend_from_slice(&source[..amount]);
61        amount
62    }
63
64    #[doc(hidden)]
65    pub fn with_limit(&mut self, limit: usize, fill: impl FnOnce(&mut RecvTarget<'_>)) -> usize {
66        let initial = self.buffer.len();
67        let previous = self.limit;
68        self.limit = initial + limit.min(self.remaining());
69        fill(self);
70        self.limit = previous;
71        self.buffer.len() - initial
72    }
73}
74
75/// An owned receive result that can be drained without allocation or
76/// knowledge of its wire-specific representation.
77pub trait RecvCursor: Unpin {
78    fn remaining(&self) -> usize;
79
80    /// Copies and consumes a logical prefix into checked uninitialized storage.
81    fn read_into(&mut self, target: &mut RecvTarget<'_>);
82
83    fn is_empty(&self) -> bool {
84        self.remaining() == 0
85    }
86}
87
88impl RecvCursor for Bytes<Retained> {
89    fn remaining(&self) -> usize {
90        self.len()
91    }
92
93    fn read_into(&mut self, target: &mut RecvTarget<'_>) {
94        let count = target.write_prefix(self.as_slice());
95        self.consume_prefix_up_to(count);
96    }
97}
98
99impl RecvCursor for View<'_> {
100    fn remaining(&self) -> usize {
101        self.len()
102    }
103
104    fn read_into(&mut self, target: &mut RecvTarget<'_>) {
105        let count = target.write_prefix(self.as_slice());
106        self.advance(count);
107    }
108}
109
110/// A connection-local receive capability offered to a retained cursor.
111///
112/// A wire claims this capability only when the cursor owns a resource that
113/// must be released before the same connection may receive again.
114#[must_use]
115pub struct RecvCredit<'d> {
116    driver: DriverRef<'d>,
117    ready: ReadyKey<'d>,
118    target: Token,
119}
120
121/// A claimed receive capability. Dropping it schedules the exact connection
122/// that supplied the capability, allowing its deferred receive stream to
123/// resume.
124#[must_use]
125pub struct RecvCreditGuard<'d>(RecvCredit<'d>);
126
127impl<'d> RecvCredit<'d> {
128    pub(crate) fn new(driver: DriverRef<'d>, ready: ReadyKey<'d>, target: Token) -> Self {
129        Self {
130            driver,
131            ready,
132            target,
133        }
134    }
135
136    pub fn claim(self) -> Result<RecvCreditGuard<'d>, Self> {
137        if !self.driver.arm_recv_credit(self.ready, self.target) {
138            return Err(self);
139        }
140        Ok(RecvCreditGuard(self))
141    }
142}
143
144impl Drop for RecvCreditGuard<'_> {
145    fn drop(&mut self) {
146        self.0
147            .driver
148            .release_recv_credit(self.0.ready, self.0.target);
149    }
150}
151
152#[derive(Clone, Copy)]
153pub struct RuntimeLimits {
154    max_connections: usize,
155    max_retained_recv_chunks: usize,
156    max_recv_len: usize,
157    recv_credit: bool,
158}
159
160impl RuntimeLimits {
161    pub fn new(
162        max_connections: usize,
163        max_retained_recv_chunks: usize,
164        max_recv_len: usize,
165    ) -> Self {
166        Self {
167            max_connections,
168            max_retained_recv_chunks,
169            max_recv_len,
170            recv_credit: false,
171        }
172    }
173
174    #[doc(hidden)]
175    pub fn with_recv_credit(mut self) -> Self {
176        self.recv_credit = true;
177        self
178    }
179
180    pub fn max_connections(self) -> usize {
181        self.max_connections
182    }
183
184    pub fn max_retained_recv_chunks(self) -> usize {
185        self.max_retained_recv_chunks
186    }
187
188    pub fn max_recv_len(self) -> usize {
189        self.max_recv_len
190    }
191
192    pub fn recv_credit(self) -> bool {
193        self.recv_credit
194    }
195}
196
197pub trait Wire: 'static + Sized {
198    /// Connection-local state, scoped to the driver domain that owns it.
199    type Connection<'d>: 'd
200    where
201        Self: 'd;
202    /// Stable storage from which connection-local state may borrow.
203    type ConnectionStorage: 'static;
204    type InitConfig<'d>: 'd
205    where
206        Self: 'd;
207    type RuntimeContext<'d>: 'd
208    where
209        Self: 'd;
210    type Open<'a, 'd>: OpenReservation<Self::Connection<'d>, Self::SendStorage>
211    where
212        'd: 'a;
213    /// A permanent failure while constructing connection-local wire state.
214    ///
215    /// Use [`std::convert::Infallible`] for wires whose open path cannot fail;
216    /// it adds no storage to the `Result<Option<_>, _>` representation.
217    type OpenError: std::error::Error + Send + Sync + 'static;
218    type Recv<'a>: RetainBytes + 'a;
219    type RecvBatch<'a>: ExactSizeIterator<Item = RecvChunk<'a, Self::Recv<'a>>>
220    where
221        Self: 'a;
222    type RetainedRecv<'d>: RecvCursor + 'd
223    where
224        Self: 'd;
225    type SendStorage: SendStorage;
226
227    const RECLAIM: Reclaim;
228
229    const RAW_RECV: bool = false;
230
231    /// Whether this wire can retain a connection-local receive credit.
232    const RECV_CREDIT: bool = false;
233
234    fn connection_storage(capacity: usize) -> io::Result<Self::ConnectionStorage>;
235
236    fn runtime_context<'d>(
237        limits: RuntimeLimits,
238        config: Self::InitConfig<'d>,
239    ) -> io::Result<Self::RuntimeContext<'d>>
240    where
241        Self: 'd;
242
243    /// Reserves wire state for one connection.
244    ///
245    /// `Ok(Some(_))` is ready to commit, `Ok(None)` is temporary backpressure,
246    /// and `Err(_)` is a permanent open failure that must be surfaced instead
247    /// of retried as capacity exhaustion.
248    fn prepare_open<'a, 'd>(
249        runtime: &'a mut Self::RuntimeContext<'d>,
250    ) -> Result<Option<Self::Open<'a, 'd>>, Self::OpenError>
251    where
252        'd: 'a;
253
254    fn holds_plain<'d>(_wire: &Self::Connection<'d>, _send: &Self::SendStorage) -> bool {
255        false
256    }
257
258    /// Transforms one unique initialized provided-buffer completion. The wire
259    /// may mutate `bytes` in place before returning borrowed ranges.
260    fn process_recv<'a, 'd>(
261        wire: &mut Self::Connection<'d>,
262        runtime: &mut Self::RuntimeContext<'d>,
263        bytes: &'a mut [u8],
264    ) -> Self::RecvBatch<'a>;
265
266    /// Transforms a receive completion whose result may outlive this call.
267    /// Ownership of the provided buffer is explicit, so a wire may retain it
268    /// directly or return an independent owned representation.
269    fn process_retained_recv<'a, 'd>(
270        wire: &mut Self::Connection<'d>,
271        runtime: &mut Self::RuntimeContext<'d>,
272        bytes: Lease<'a>,
273    ) -> Option<Self::RetainedRecv<'a>>;
274
275    /// Claims a connection-local receive credit for a retained cursor.
276    ///
277    /// The default leaves receive flow unchanged. A wire returns `Ok(())` only
278    /// after `credit.claim()` succeeds and stores the resulting guard in
279    /// `recv`. It releases that guard as soon as the resource imposing
280    /// backpressure is released.
281    fn bind_recv_credit<'d>(
282        recv: &mut Self::RetainedRecv<'d>,
283        credit: RecvCredit<'d>,
284    ) -> Result<(), RecvCredit<'d>> {
285        let _ = recv;
286        Err(credit)
287    }
288
289    fn recv_eof<'d>(_wire: &mut Self::Connection<'d>) {}
290
291    fn prepare_send<'a, 'd>(
292        wire: &'a mut Self::Connection<'d>,
293        send: Storage<'a, Self::SendStorage>,
294        plain: Plain<'a>,
295    ) -> Prepared<'a>;
296
297    fn prepare_send_vectored<'a, 'd>(
298        wire: &'a mut Self::Connection<'d>,
299        send: Storage<'a, Self::SendStorage>,
300        plain: Vectored<'a>,
301    ) -> Prepared<'a>;
302
303    fn submit_failed<'d>(_wire: &mut Self::Connection<'d>) {}
304
305    fn after_send<'a, 'd>(
306        wire: &'a mut Self::Connection<'d>,
307        send: Storage<'a, Self::SendStorage>,
308        sent: Sent,
309    ) -> Prepared<'a>;
310
311    fn flush_pending<'a, 'd>(
312        wire: &'a mut Self::Connection<'d>,
313        send: Storage<'a, Self::SendStorage>,
314    ) -> Prepared<'a>;
315
316    fn graceful_close<'a, 'd>(
317        _wire: &'a mut Self::Connection<'d>,
318        send: Storage<'a, Self::SendStorage>,
319    ) -> Prepared<'a> {
320        send.empty(0)
321    }
322}
323
324pub trait OpenReservation<W, S> {
325    fn commit(self) -> (W, S);
326}
327
328pub trait OpenRollback<W, S> {
329    fn rollback_open(&mut self, open: (W, S));
330}
331
332pub struct ReadyOpen<W, S> {
333    committed: (W, S),
334}
335
336impl<W, S> ReadyOpen<W, S> {
337    pub fn new(wire: W, send: S) -> Self {
338        Self {
339            committed: (wire, send),
340        }
341    }
342}
343
344impl<W, S> OpenReservation<W, S> for ReadyOpen<W, S> {
345    fn commit(self) -> (W, S) {
346        self.committed
347    }
348}