Skip to main content

sark_core/life/
mod.rs

1//! Protocol-neutral evidence committed by lifecycle owners.
2
3use std::{convert::Infallible, fmt};
4
5use hold::evidence;
6use o3::buffer::{hold, segments};
7use sark_http::owner::{self, evidence::Cause};
8
9use crate::{body::credit, deadline};
10
11pub mod audit;
12pub mod endpoint;
13pub mod exchange;
14pub mod mode;
15pub mod owners;
16pub mod response;
17pub mod sequence;
18pub mod session;
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
21pub enum Outcome {
22    Completed,
23    Cancelled,
24    Rejected,
25}
26
27#[derive(Clone, Copy, PartialEq, Eq)]
28pub enum Event<C, S> {
29    SessionOpened(C),
30    SessionEstablished(C),
31    ExchangeOpened(exchange::Id<C, S>),
32    HeadAdmitted(exchange::Id<C, S>),
33    PreAdmissionReserved {
34        exchange: exchange::Id<C, S>,
35        bytes: usize,
36        chunks: segments::Count,
37    },
38    PreAdmissionReleased {
39        exchange: exchange::Id<C, S>,
40        bytes: usize,
41        chunks: segments::Count,
42    },
43    RequestOwnerAcquired {
44        exchange: exchange::Id<C, S>,
45        charge: owners::Request,
46    },
47    RequestOwnerScopeClosed(exchange::Id<C, S>),
48    InputFinished(exchange::Id<C, S>),
49    BuildReady(exchange::Id<C, S>),
50    TaskAdmitted(exchange::Id<C, S>),
51    TaskPollPending(exchange::Id<C, S>),
52    TaskPollReady(exchange::Id<C, S>),
53    TaskCancelled(exchange::Id<C, S>),
54    ResponseCommitted {
55        exchange: exchange::Id<C, S>,
56        body_bytes: usize,
57        charge: hold::Charge,
58        linked: hold::Charge,
59    },
60    ResponseBodyCopied {
61        exchange: exchange::Id<C, S>,
62        read: usize,
63        written: usize,
64        cause: Cause,
65    },
66    ResponseOwnership(owner::Effect<exchange::Id<C, S>>),
67    Terminal {
68        exchange: exchange::Id<C, S>,
69        outcome: Outcome,
70    },
71    ExchangeDeadlineExpired {
72        exchange: exchange::Id<C, S>,
73        phase: deadline::Phase,
74    },
75    ExchangeRetired(exchange::Id<C, S>),
76    SessionClosing(C),
77    SessionClosed(C),
78}
79
80pub trait Observer<C: Copy, S: Copy> {
81    fn observe(&mut self, event: Event<C, S>);
82
83    /// Observes a borrowed local cause without changing lifecycle decisions.
84    fn diagnostic<E: fmt::Debug>(&mut self, cause: &E);
85
86    fn audit(&mut self, conn: C, state: audit::Snapshot);
87}
88
89impl<C: Copy, S: Copy> Observer<C, S> for Infallible {
90    fn diagnostic<E: fmt::Debug>(&mut self, _: &E) {
91        match *self {}
92    }
93
94    fn observe(&mut self, _: Event<C, S>) {
95        match *self {}
96    }
97
98    fn audit(&mut self, _: C, _: audit::Snapshot) {
99        match *self {}
100    }
101}
102
103pub trait Mode<C: Copy, S: Copy> {
104    const ENABLED: bool;
105
106    /// Whether response commits need exact retained-owner charges.
107    const RESPONSE_CHARGE: bool = true;
108
109    type Retention: evidence::Mode;
110    type Observer: Observer<C, S>;
111
112    type Body<'a>: credit::Evidence
113    where
114        Self: 'a,
115        C: 'a,
116        S: 'a;
117
118    fn observer(&mut self) -> Option<&mut Self::Observer>;
119
120    fn observe(&mut self, event: Event<C, S>) {
121        if let Some(out) = self.observer() {
122            out.observe(event);
123        }
124    }
125
126    /// Observes a borrowed local cause without changing lifecycle decisions.
127    fn diagnostic<E: fmt::Debug>(&mut self, cause: &E) {
128        if let Some(out) = self.observer() {
129            out.diagnostic(cause);
130        }
131    }
132
133    fn audit<F>(&mut self, conn: C, get: F)
134    where
135        F: FnOnce() -> audit::Snapshot,
136    {
137        if let Some(out) = self.observer() {
138            out.audit(conn, get());
139        }
140    }
141
142    fn body<'a>(&'a mut self, id: exchange::Id<C, S>) -> Self::Body<'a>
143    where
144        C: 'a,
145        S: 'a;
146
147    fn close<F>(&mut self, conn: C, get: F)
148    where
149        F: FnOnce() -> audit::Snapshot,
150    {
151        let out = match self.observer() {
152            Some(out) => out,
153            None => return,
154        };
155        out.audit(conn, get());
156        out.observe(Event::SessionClosed(conn));
157    }
158}
159
160pub struct BodyScope<'a, C, S, O> {
161    pub(crate) id: exchange::Id<C, S>,
162    pub(crate) out: &'a mut O,
163}
164
165impl<C: Copy, S: Copy, O: Observer<C, S>> credit::Evidence for BodyScope<'_, C, S, O> {
166    type Change = credit::Mutation;
167
168    fn record(&mut self, change: credit::Mutation) {
169        match change {
170            credit::Mutation::Head => {
171                self.out.observe(Event::HeadAdmitted(self.id));
172            }
173            credit::Mutation::Reserved(credit) => {
174                self.out.observe(Event::PreAdmissionReserved {
175                    exchange: self.id,
176                    bytes: credit.bytes(),
177                    chunks: credit.chunks(),
178                });
179            }
180            credit::Mutation::Released {
181                credit,
182                disposition: kind,
183            } => {
184                self.out.observe(Event::PreAdmissionReleased {
185                    exchange: self.id,
186                    bytes: credit.bytes(),
187                    chunks: credit.chunks(),
188                });
189                if kind == credit::Disposition::Admitted {
190                    self.out.observe(Event::RequestOwnerAcquired {
191                        exchange: self.id,
192                        charge: owners::Request::new(credit.bytes(), credit.chunks()),
193                    });
194                }
195            }
196            credit::Mutation::BuildReady => self.out.observe(Event::BuildReady(self.id)),
197        }
198    }
199}
200
201#[must_use = "finish protocol cleanup, then consume the expiry"]
202pub struct Expiry<C: Copy, S: Copy> {
203    exchange: exchange::Id<C, S>,
204    phase: deadline::Phase,
205}
206
207impl<C: Copy, S: Copy> Expiry<C, S> {
208    pub(crate) const fn new(id: exchange::Id<C, S>, phase: deadline::Phase) -> Self {
209        Self {
210            exchange: id,
211            phase,
212        }
213    }
214
215    pub const fn exchange(&self) -> exchange::Id<C, S> {
216        self.exchange
217    }
218
219    pub const fn phase(&self) -> deadline::Phase {
220        self.phase
221    }
222
223    pub fn finish<M: Mode<C, S>>(self, mode: &mut M) {
224        self.exchange.retire(mode, Outcome::Cancelled);
225    }
226}