1use 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 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 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 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}