1impl<'de> Deserialize<'de> for SessionState {
2 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3 where
4 D: serde::Deserializer<'de>,
5 {
6 let raw = SessionStateSerde::deserialize(deserializer)?;
7 let mut session = Self {
8 sid: raw.sid,
9 roles: raw.roles,
10 role_ids: BTreeMap::new(),
11 local_types: raw.local_types,
12 buffers: raw.buffers,
13 edge_lookup: BTreeMap::new(),
14 handler_ids: BTreeMap::new(),
15 handlers_by_id: Vec::new(),
16 edge_handler_lookup: BTreeMap::new(),
17 default_handler_id: None,
18 label_ids: BTreeMap::new(),
19 labels_by_id: Vec::new(),
20 branch_lookup: BTreeMap::new(),
21 auth_leaves: raw.auth_leaves,
22 auth_trees: raw.auth_trees,
23 auth_roots: raw.auth_roots,
24 edge_handlers: raw.edge_handlers,
25 default_handler: raw.default_handler,
26 edge_traces: raw.edge_traces,
27 status: raw.status,
28 epoch: raw.epoch,
29 };
30 session.rebuild_derived_indexes();
31 Ok(session)
32 }
33}
34
35#[derive(Debug, Default, Serialize, Deserialize)]
40pub struct SessionStore {
41 sessions: BTreeMap<SessionId, SessionState>,
42 #[serde(default)]
43 archived_closed: Vec<ClosedSessionSummary>,
44 next_id: SessionId,
45}
46
47impl SessionStore {
48 #[must_use]
50 pub fn new() -> Self {
51 Self::default()
52 }
53
54 #[allow(clippy::needless_pass_by_value)]
58 pub fn open_with_sid(
59 &mut self,
60 sid: SessionId,
61 roles: Vec<String>,
62 buffer_config: &BufferConfig,
63 initial_types: &BTreeMap<String, LocalTypeR>,
64 ) -> SessionId {
65 let plan = SessionOpenPlan::new(&roles, initial_types);
66 self.open_with_sid_from_plan(sid, &plan, buffer_config)
67 }
68
69 pub fn open_with_sid_from_plan(
71 &mut self,
72 sid: SessionId,
73 plan: &SessionOpenPlan,
74 buffer_config: &BufferConfig,
75 ) -> SessionId {
76 let state = SessionState::from_open_plan(sid, plan, buffer_config);
77 self.sessions.insert(sid, state);
78 self.next_id = self.next_id.max(sid.saturating_add(1));
79 sid
80 }
81
82 #[allow(clippy::needless_pass_by_value)]
86 pub fn open(
87 &mut self,
88 roles: Vec<String>,
89 buffer_config: &BufferConfig,
90 initial_types: &BTreeMap<String, LocalTypeR>,
91 ) -> SessionId {
92 let sid = self.next_id;
93 self.open_with_sid(sid, roles, buffer_config, initial_types)
94 }
95
96 #[must_use]
98 pub fn next_session_id(&self) -> SessionId {
99 self.next_id
100 }
101
102 #[must_use]
108 pub fn lookup_type(&self, ep: &Endpoint) -> Option<&LocalTypeR> {
109 self.sessions
110 .get(&ep.sid)?
111 .local_types
112 .get(ep)
113 .map(|e| &e.current)
114 }
115
116 pub fn update_type(&mut self, ep: &Endpoint, new_type: LocalTypeR) {
120 if let Some(session) = self.sessions.get_mut(&ep.sid) {
121 if let Some(entry) = session.local_types.get_mut(ep) {
122 entry.current = new_type;
123 }
124 session.refresh_endpoint_branch_lookup(ep);
125 }
126 }
127
128 pub fn update_original(&mut self, ep: &Endpoint, new_original: LocalTypeR) {
130 if let Some(session) = self.sessions.get_mut(&ep.sid) {
131 if let Some(entry) = session.local_types.get_mut(ep) {
132 entry.original = new_original;
133 }
134 }
135 }
136
137 #[must_use]
139 pub fn original_type(&self, ep: &Endpoint) -> Option<&LocalTypeR> {
140 self.sessions
141 .get(&ep.sid)?
142 .local_types
143 .get(ep)
144 .map(|e| &e.original)
145 }
146
147 pub fn remove_type(&mut self, ep: &Endpoint) {
149 if let Some(session) = self.sessions.get_mut(&ep.sid) {
150 session.local_types.remove(ep);
151 session.branch_lookup.remove(ep);
152 }
153 }
154
155 #[must_use]
159 pub fn get(&self, sid: SessionId) -> Option<&SessionState> {
160 self.sessions.get(&sid)
161 }
162
163 pub fn get_mut(&mut self, sid: SessionId) -> Option<&mut SessionState> {
165 self.sessions.get_mut(&sid)
166 }
167
168 pub fn iter(&self) -> impl Iterator<Item = &SessionState> {
170 self.sessions.values()
171 }
172
173 pub fn close(&mut self, sid: SessionId) -> Result<(), String> {
179 let session = self
180 .sessions
181 .get_mut(&sid)
182 .ok_or_else(|| format!("session {sid} not found"))?;
183
184 session.status = SessionStatus::Closed;
185 session.buffers.clear();
186 session.edge_traces.clear();
187 session.epoch = session.epoch.saturating_add(1);
188 Ok(())
189 }
190
191 #[must_use]
193 pub fn closed_session_ids(&self) -> Vec<SessionId> {
194 self.sessions
195 .iter()
196 .filter_map(|(sid, session)| {
197 matches!(
198 session.status,
199 SessionStatus::Closed
200 | SessionStatus::Cancelled
201 | SessionStatus::Faulted { .. }
202 )
203 .then_some(*sid)
204 })
205 .collect()
206 }
207
208 pub fn reap_sessions(&mut self, session_ids: &[SessionId]) -> Vec<ClosedSessionSummary> {
215 let mut reaped = Vec::new();
216 for sid in session_ids {
217 let Some(session) = self.sessions.get(sid) else {
218 continue;
219 };
220 if !matches!(
221 session.status,
222 SessionStatus::Closed | SessionStatus::Cancelled | SessionStatus::Faulted { .. }
223 ) {
224 continue;
225 }
226
227 let session = self
228 .sessions
229 .remove(sid)
230 .expect("session existence checked before removal");
231 let summary = ClosedSessionSummary::from_session(&session);
232 self.archived_closed.push(summary.clone());
233 reaped.push(summary);
234 }
235 reaped
236 }
237
238 pub fn reap_closed(&mut self) -> Vec<ClosedSessionSummary> {
240 let sids = self.closed_session_ids();
241 self.reap_sessions(&sids)
242 }
243
244 #[must_use]
246 pub fn active_count(&self) -> usize {
247 self.sessions
248 .values()
249 .filter(|s| s.status == SessionStatus::Active)
250 .count()
251 }
252
253 #[must_use]
255 pub fn live_count(&self) -> usize {
256 self.sessions.len()
257 }
258
259 #[must_use]
261 pub fn session_ids(&self) -> Vec<SessionId> {
262 self.sessions.keys().copied().collect()
263 }
264
265 #[must_use]
267 pub fn archived_closed(&self) -> &[ClosedSessionSummary] {
268 &self.archived_closed
269 }
270
271 #[must_use]
273 pub fn memory_usage(&self) -> SessionStoreMemoryUsage {
274 let mut usage = SessionStoreMemoryUsage {
275 live_sessions: self.sessions.len(),
276 archived_closed_sessions: self.archived_closed.len(),
277 ..SessionStoreMemoryUsage::default()
278 };
279 usage.retained_bytes.archived_closed = self
280 .archived_closed
281 .iter()
282 .map(ClosedSessionSummary::retained_bytes_estimate)
283 .sum();
284
285 for session in self.sessions.values() {
286 if matches!(
287 session.status,
288 SessionStatus::Closed | SessionStatus::Cancelled | SessionStatus::Faulted { .. }
289 ) {
290 usage.live_closed_sessions += 1;
291 }
292 usage.live_local_type_entries += session.local_types.len();
293 usage.live_buffer_count += session.buffers.len();
294 usage.live_buffered_messages += session
295 .buffers
296 .values()
297 .map(BoundedBuffer::len)
298 .sum::<usize>();
299 usage.live_edge_handler_count += session.edge_handlers.len();
300 usage.live_auth_leaf_count += session.auth_leaves.values().map(Vec::len).sum::<usize>();
301 usage.live_auth_tree_count += session.auth_trees.len();
302 usage.live_auth_root_count += session.auth_roots.len();
303 usage.retained_bytes.live_sessions += session.retained_session_core_bytes();
304 usage.retained_bytes.local_types += session.retained_local_type_bytes();
305 usage.retained_bytes.buffers += session.retained_buffer_bytes();
306 usage.retained_bytes.traces += session.retained_trace_bytes();
307 usage.retained_bytes.auth += session.retained_auth_bytes();
308 usage.retained_bytes.handlers += session.retained_handler_bytes();
309 }
310 usage.retained_bytes.total = usage
311 .retained_bytes
312 .live_sessions
313 .saturating_add(usage.retained_bytes.archived_closed)
314 .saturating_add(usage.retained_bytes.local_types)
315 .saturating_add(usage.retained_bytes.buffers)
316 .saturating_add(usage.retained_bytes.traces)
317 .saturating_add(usage.retained_bytes.auth)
318 .saturating_add(usage.retained_bytes.handlers);
319
320 usage
321 }
322
323 #[must_use]
325 pub fn lookup_handler(&self, edge: &Edge) -> Option<&HandlerId> {
326 self.sessions
327 .get(&edge.sid)?
328 .lookup_handler_for_roles(&edge.sender, &edge.receiver)
329 }
330
331 #[must_use]
333 pub fn default_handler_for_session(&self, sid: SessionId) -> Option<&HandlerId> {
334 self.sessions.get(&sid)?.default_handler_binding()
335 }
336
337 pub fn set_default_handler_for_session(&mut self, sid: SessionId, handler: HandlerId) {
339 if let Some(session) = self.sessions.get_mut(&sid) {
340 let handler_id = session.intern_handler_binding(&handler);
341 session.default_handler = handler;
342 session.default_handler_id = Some(handler_id);
343 }
344 }
345
346 pub fn update_handler(&mut self, edge: &Edge, handler: HandlerId) {
348 if let Some(session) = self.sessions.get_mut(&edge.sid) {
349 let handler_id = session.intern_handler_binding(&handler);
350 if let Some(edge_key) = session.edge_key_for_roles(&edge.sender, &edge.receiver) {
351 session.edge_handler_lookup.insert(edge_key, handler_id);
352 }
353 session.edge_handlers.insert(edge.clone(), handler);
354 }
355 }
356
357 #[must_use]
359 pub fn lookup_trace(&self, edge: &Edge) -> Option<&[ValType]> {
360 self.sessions
361 .get(&edge.sid)?
362 .edge_traces
363 .get(edge)
364 .map(Vec::as_slice)
365 }
366
367 pub fn update_trace(&mut self, edge: &Edge, trace: Vec<ValType>) {
369 if let Some(session) = self.sessions.get_mut(&edge.sid) {
370 session.edge_traces.insert(edge.clone(), trace);
371 }
372 }
373}
374
375#[must_use]
381pub fn unfold_mu(lt: &LocalTypeR) -> LocalTypeR {
383 match lt {
384 LocalTypeR::Mu { body, .. } => unfold_mu(body),
385 other => other.clone(),
386 }
387}
388
389#[must_use]
394pub fn unfold_if_var(cont: &LocalTypeR, original: &LocalTypeR) -> LocalTypeR {
395 match cont {
396 LocalTypeR::Var(_) => unfold_mu(original),
397 LocalTypeR::Mu { .. } => unfold_mu(cont),
398 other => other.clone(),
399 }
400}
401
402#[must_use]
408pub fn unfold_if_var_with_scope(
409 cont: &LocalTypeR,
410 original: &LocalTypeR,
411) -> (LocalTypeR, Option<LocalTypeR>) {
412 match cont {
413 LocalTypeR::Var(_) => (unfold_mu(original), None),
414 LocalTypeR::Mu { .. } => (unfold_mu(cont), Some(cont.clone())),
415 other => (other.clone(), None),
416 }
417}