dope-manifold 0.37.0

Owned application and service composition for dope
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
use std::{convert::Infallible, marker::PhantomData};

use dope_core::{
    driver::{
        self,
        route::{Identity, KeyTag},
        schedule::{self, app::Permit, clock},
    },
    io::socket,
};
use dope_net::{
    link::{
        egress::{self, data},
        pool::{change::opening, recv::input},
    },
    wire::{domain, open, receive::Chunk, terminal},
};
use o3::{
    base::{Call, cell::region, time::Positive},
    buffer::bytes,
    mem::rc,
};

use crate::{
    app::{
        Park,
        receive::{self, limits},
    },
    client::{
        self, attempt, close,
        conn::{self, drain},
    },
};

pub mod admit;
pub mod defer;
pub mod failure;
mod policy;
mod receiver;
pub mod request;
pub mod resume;

pub(in crate::client) use policy::Policy;
pub(in crate::client) use receiver::Receiver;
pub mod connect;

pub trait Borrowed<'d, ID: Identity = KeyTag<0>>:
    Receive<'d, ID, Input = receive::Borrowed, Continuation: resume::Mode<Retention = resume::Absent>>
{
    fn chunk<'e, O, R: bytes::TryRetain>(
        &mut self,
        conn: conn::Ctx<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        chunk: R,
        driver: &mut driver::Context<'_, 'd>,
    ) -> ChunkOutcome;
}

pub trait Owned<'w, 'd: 'w, ID: Identity = KeyTag<0>, R: Default = ()>:
    Receive<'d, ID, Input = receive::Owned<R>>
{
    const RETENTION: limits::Retention;

    /// Supplies this instance's receive-credit bound once during installation.
    fn retention(&self) -> limits::Retention {
        Self::RETENTION
    }

    fn chunk<'e, O>(
        &mut self,
        conn: conn::Ctx<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        chunk: Chunk<'w, 'd, Self::Wire>,
        receipt: R,
        driver: &mut driver::Context<'_, 'd>,
    ) -> <Self::Continuation as resume::Mode>::Outcome;
}

/// Exact typed completion result for a delivered receive chunk.
#[must_use = "the receive result must be applied to the connection"]
#[repr(transparent)]
pub struct ChunkOutcome(Result<(), receive::Failure>);

impl ChunkOutcome {
    pub const fn ok() -> Self {
        Self(Ok(()))
    }

    pub const fn failed(cause: receive::Failure) -> Self {
        Self(Err(cause))
    }

    pub const fn into_result(self) -> Result<(), receive::Failure> {
        self.0
    }
}

const _: () = assert!(size_of::<ChunkOutcome>() == size_of::<receive::Failure>());

pub enum Resumed {
    Complete(ChunkOutcome),
    Paused(Pause),
}

/// Scheduling result for incomplete resumable receive work.
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Pause {
    Yield,
    Blocked,
}

const _: () = assert!(size_of::<Resumed>() == size_of::<ChunkOutcome>());

#[derive(Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub enum Wake {
    Idle,
    Ready,
}

#[derive(Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub enum Eof {
    Close,
    Retain,
}

#[derive(Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub enum Fence {
    Ready,
    Pending,
}

const _: () = {
    assert!(size_of::<Wake>() == 1);
    assert!(size_of::<Eof>() == 1);
    assert!(size_of::<Fence>() == 1);
};

pub enum CloseOutcome {
    Complete(close::Directive),
    /// Cleanup can continue in another admitted turn.
    Yield,
    /// Cleanup retains its owners until an external wake or cancellation.
    Blocked,
}

/// Application admission for one transport-connected primary generation.
/// Rejection retires only transport ownership; no application retirement
/// callback is emitted for a generation that was never attached.
#[must_use = "connection admission must be committed or rejected"]
pub enum Admission {
    /// Application ownership is live until one matching `drained`.
    Attached,
    /// No application ownership remains; retire the physical transport only.
    Rejected(close::Directive),
}

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Inbound {
    /// No protocol response is currently expected, so inbound silence is safe.
    Quiescent,
    /// A response is outstanding and must make inbound progress within this window.
    Awaiting(Positive),
}

pub trait Application<'d, ID: Identity = KeyTag<0>>: Sized {
    type Conn;
    type Connect: connect::Mode;
    type Deferred: defer::Mode;
    type Failure: failure::Mode;
    type Wire: input::Execution + 'd;
    type Send: data::raw::Payload<'d>;
    type Input: receive::Mode<Self::Wire>;
    type Requests: request::Mode;

    fn try_conn(&self) -> Result<Self::Conn, rc::Error>;
}

pub trait Receive<'d, ID: Identity = KeyTag<0>>: Application<'d, ID> {
    type Continuation: resume::Mode;

    fn receipt(
        &self,
        _: conn::Id<'d, ID>,
        _: &Self::Conn,
        _: &region::Token<region::Identity<'d, 0>>,
    ) -> <Self::Input as input::Mode<Self::Wire>>::Receipt {
        Default::default()
    }

    /// Stops new admission; pending work keeps receiving until the next inspection.
    fn withdraw(&mut self, _: conn::Id<'d, ID>, _: &mut Self::Conn) -> Fence {
        Fence::Ready
    }

    /// Classifies application-owned retained state for connection retirement.
    fn quiesce<'a>(
        &self,
        barrier: Barrier<'a, 'd, ID>,
        driver: &mut driver::Context<'_, 'd>,
    ) -> Drain<'a, 'd, ID>;

    /// Observes orderly input end and whether the wire also ended output.
    fn eof<'e, O>(
        &mut self,
        _: conn::Ctx<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        _: receive::End,
        _: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        _: &mut driver::Context<'_, 'd>,
    ) -> Eof {
        Eof::Close
    }

    fn fence<O>(
        &self,
        _: conn::Ref<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        _: &mut driver::Context<'_, 'd>,
    ) -> Fence {
        Fence::Ready
    }
}

pub trait Resumable<'d, ID: Identity = KeyTag<0>>: Receive<'d, ID> {
    /// Returns the resident capacity owned by retained receive storage.
    fn resident(&self) -> domain::Resident;

    /// Consumes an application-owned blocked marker for this connection.
    /// `Ready` asks the engine to retry its exact retained receive.
    fn wake(&mut self, conn: &mut Self::Conn) -> Wake;

    /// Describes whether this exact connection is waiting for inbound progress.
    fn inbound<O>(
        &self,
        conn: conn::Ref<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        base: Positive,
        driver: &mut driver::Context<'_, 'd>,
    ) -> Inbound;

    fn resume<'e, 'turn, O>(
        &mut self,
        permit: Permit<'turn, 'd>,
        conn: conn::Ctx<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        driver: &mut driver::Context<'_, 'd>,
    ) -> <Self::Continuation as resume::Mode>::Outcome;
}

/// Move-only authority to classify one exact connection's application drain.
#[must_use = "drain authority must produce an exact outcome"]
#[repr(transparent)]
pub struct Barrier<'a, 'd, ID: Identity>(
    &'a drain::Drain<'d, ID>,
    PhantomData<fn(&'a ()) -> &'a ()>,
);

impl<'a, 'd, ID: Identity> Barrier<'a, 'd, ID> {
    pub(in crate::client) const fn new(drain: &'a drain::Drain<'d, ID>) -> Self {
        Self(drain, PhantomData)
    }

    pub const fn connection(&self) -> conn::Id<'d, ID> {
        self.0.connection()
    }

    pub const fn pending(self) -> Drain<'a, 'd, ID> {
        Drain(None)
    }

    pub const fn ready(self) -> Drain<'a, 'd, ID> {
        Drain(Some(self))
    }
}

/// Exact application-drain result for one connection generation.
#[must_use = "drain outcome must reach connection retirement"]
#[repr(transparent)]
pub struct Drain<'a, 'd, ID: Identity>(Option<Barrier<'a, 'd, ID>>);

pub(in crate::client) enum Resolution<'d, ID: Identity> {
    Pending,
    Ready(Quiesced<'d, ID>),
}

impl<'a, 'd, ID: Identity> Drain<'a, 'd, ID> {
    pub(in crate::client) const fn resolve(self) -> Resolution<'d, ID> {
        match self.0 {
            None => Resolution::Pending,
            Some(barrier) => Resolution::Ready(Quiesced(barrier.connection())),
        }
    }
}

/// Move-only proof that one exact connection's application state is quiescent.
#[must_use = "quiescence proof must reach connection retirement"]
#[repr(transparent)]
pub struct Quiesced<'d, ID: Identity>(conn::Id<'d, ID>);

impl<'d, ID: Identity> Quiesced<'d, ID> {
    pub const fn connection(&self) -> conn::Id<'d, ID> {
        self.0
    }
}

const _: () = {
    assert!(
        size_of::<Barrier<'static, 'static, KeyTag<0>>>()
            == size_of::<&conn::Id<'static, KeyTag<0>>>()
    );
    assert!(size_of::<Quiesced<'static, KeyTag<0>>>() == size_of::<conn::Id<'static, KeyTag<0>>>());
    assert!(size_of::<Drain<'static, 'static, KeyTag<0>>>() == size_of::<usize>());
    assert!(
        std::mem::align_of::<Drain<'static, 'static, KeyTag<0>>>() == std::mem::align_of::<usize>()
    );
};

pub trait Lifecycle<'w, 'd: 'w, ID: Identity = KeyTag<0>>: Receive<'d, ID> {
    /// Consumes pending close control through native retirement.
    fn take_close(&self, _: conn::Id<'d, ID>) -> Option<close::Directive> {
        None
    }

    fn prepare<'e, O>(
        &mut self,
        conn: conn::Ctx<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        queued: bool,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        driver: &mut driver::Context<'_, 'd>,
    );

    fn sent(
        &mut self,
        conn: conn::Id<'d, ID>,
        pending: egress::Pending,
        token: &mut region::Token<region::Identity<'d, 1>>,
    );

    fn cancel(&mut self, payload: Self::Send, token: &mut region::Token<region::Identity<'d, 1>>);

    /// Observes the exact owned wire receive failure before transport teardown.
    fn wire_fail<'e, O>(
        &mut self,
        conn: conn::Io<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        cause: terminal::Error<'w, Self::Wire>,
        driver: &mut driver::Context<'_, 'd>,
    );

    /// Observes the exact transport receive failure before teardown.
    fn io_fail<'e, O>(
        &mut self,
        conn: conn::Io<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        error: dope_core::Errno,
        driver: &mut driver::Context<'_, 'd>,
    );

    fn close<'e, O>(
        &mut self,
        conn: conn::Ctx<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        reason: close::Reason,
        driver: &mut driver::Context<'_, 'd>,
    ) -> CloseOutcome;

    /// Finalizes application state only after transport send/receive ownership
    /// and the exact connection's egress queue have been retired.
    fn drained(
        &mut self,
        proof: conn::Retired<'d, ID, Self>,
        state: &mut Self::Conn,
        driver: &mut driver::Context<'_, 'd>,
    );
}

pub trait Deferred<'d, ID: Identity = KeyTag<0>>:
    Application<'d, ID, Deferred = defer::Observed>
{
    fn deferred(
        &mut self,
        key: attempt::Id<'d, ID>,
        cause: opening::Deferred,
        driver: &mut driver::Context<'_, 'd>,
    );
}

pub trait Opened<'w, 'd: 'w, ID: Identity = KeyTag<0>>: Application<'d, ID> {
    fn open(
        &mut self,
        key: attempt::Completion<'_, 'd, ID>,
        cause: open::Error<'w, Self::Wire>,
        driver: &mut driver::Context<'_, 'd>,
    );
}

pub trait Connected<'d, ID: Identity = KeyTag<0>>:
    Application<'d, ID, Connect = connect::Full>
{
    type Activation: admit::Dispatch<'d, ID, Self>;

    fn connected<'e, O>(
        &mut self,
        key: attempt::Completion<'_, 'd, ID>,
        peer: socket::Addr,
        conn: conn::Established<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        driver: &mut driver::Context<'_, 'd>,
    );
}

pub trait Peer<'d, ID: Identity = KeyTag<0>>: Application<'d, ID, Connect = connect::Peer> {
    type Addr;

    fn connected<'e, O>(
        &mut self,
        peer: Self::Addr,
        conn: conn::Ctx<'_, 'd, ID, Self::Wire, Self::Conn, O>,
        egress: egress::Queue<'_, 'e, 'd, { client::IOV_CAP }, Self::Send>,
        driver: &mut driver::Context<'_, 'd>,
    );
}

pub trait Exhausted<'d, ID: Identity = KeyTag<0>>: Application<'d, ID> {
    fn exhaust(
        &mut self,
        key: attempt::Completion<'_, 'd, ID>,
        cause: opening::Exhaustion,
        driver: &mut driver::Context<'_, 'd>,
    );
}

pub trait Failed<'d, ID: Identity = KeyTag<0>>:
    Exhausted<'d, ID> + Application<'d, ID, Failure = failure::Observed>
{
    fn failed(
        &mut self,
        key: attempt::Completion<'_, 'd, ID>,
        cause: attempt::ConnectFault,
        driver: &mut driver::Context<'_, 'd>,
    );
}

pub trait Requests<'d, ID: Identity = KeyTag<0>>:
    Application<'d, ID, Requests = request::Enabled>
{
    fn drain<'e>(&self, turn: &mut request::Turn<'_, 'e, 'd, Self::Conn, Self::Send, ID>);
}

pub trait Scheduling<'d, ID: Identity = KeyTag<0>>: Application<'d, ID> {
    fn park() -> Option<impl for<'a, 'b, 'c, 'e> Call<(&'a mut Self, &'b mut Park<'c, 'e, 'd>)>> {
        None::<Infallible>
    }

    /// Starts application-owned retained-state retirement. The engine calls
    /// this exactly once before it begins closing connection slots.
    fn shutdown() -> Option<impl for<'a> Call<&'a mut Self>> {
        None::<Infallible>
    }

    fn progress(
        &self,
        region: &region::Token<region::Identity<'d>>,
        clock: clock::Clock<'_, 'd>,
    ) -> schedule::Progress<'d>;
}