eredu_core/
session_authority.rs1use std::sync::{
4 atomic::{AtomicU64, Ordering},
5 Arc,
6};
7
8use crate::SessionCapabilities;
9
10#[derive(Debug, Clone, Copy, Eq, PartialEq)]
12pub struct SessionAdmission {
13 capabilities: SessionCapabilities,
14}
15
16impl SessionAdmission {
17 pub const fn new(capabilities: SessionCapabilities) -> Self {
19 Self { capabilities }
20 }
21
22 pub fn validate(self, realized: SessionCapabilities) -> Result<(), SessionAdmissionError> {
24 if self.capabilities == realized {
25 Ok(())
26 } else {
27 Err(SessionAdmissionError {
28 admitted: self.capabilities,
29 realized,
30 })
31 }
32 }
33}
34
35#[derive(Debug, Clone, Copy, Eq, PartialEq, thiserror::Error)]
37#[error("realized session capabilities {realized:?} do not match pre-materialization admission {admitted:?}")]
38pub struct SessionAdmissionError {
39 admitted: SessionCapabilities,
40 realized: SessionCapabilities,
41}
42
43impl SessionAdmissionError {
44 pub const fn admitted(self) -> SessionCapabilities {
46 self.admitted
47 }
48
49 pub const fn realized(self) -> SessionCapabilities {
51 self.realized
52 }
53}
54
55#[derive(Debug)]
62pub struct SessionAuthority {
63 active: Arc<AtomicU64>,
64 next_ticket: u64,
65}
66
67impl Default for SessionAuthority {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73impl SessionAuthority {
74 pub fn new() -> Self {
76 Self {
77 active: Arc::new(AtomicU64::new(0)),
78 next_ticket: 1,
79 }
80 }
81
82 pub fn require_idle(&self) -> Result<(), SessionAuthorityError> {
84 if self.active.load(Ordering::Acquire) == 0 {
85 Ok(())
86 } else {
87 Err(SessionAuthorityError::Busy)
88 }
89 }
90
91 pub fn begin_submission(&mut self) -> Result<SubmissionLease, SessionAuthorityError> {
97 self.require_idle()?;
98 let ticket = self.next_ticket;
99 self.next_ticket = ticket
100 .checked_add(1)
101 .ok_or(SessionAuthorityError::TicketExhausted)?;
102 self.active.store(ticket, Ordering::Release);
103 Ok(SubmissionLease {
104 owner: Arc::clone(&self.active),
105 ticket,
106 })
107 }
108}
109
110#[derive(Debug, Clone, Copy, Eq, PartialEq, thiserror::Error)]
112#[non_exhaustive]
113pub enum SessionAuthorityError {
114 #[error("model session already owns an unresolved submission completion")]
116 Busy,
117 #[error("model session submission ticket space exhausted")]
119 TicketExhausted,
120}
121
122#[derive(Debug)]
129#[must_use = "the submission lease must be retained until native work is safely resolved"]
130pub struct SubmissionLease {
131 owner: Arc<AtomicU64>,
132 ticket: u64,
133}
134
135impl SubmissionLease {
136 pub fn resolve(&self) -> bool {
141 self.owner
142 .compare_exchange(self.ticket, 0, Ordering::AcqRel, Ordering::Acquire)
143 .is_ok()
144 }
145}
146
147impl Drop for SubmissionLease {
148 fn drop(&mut self) {
149 self.resolve();
150 }
151}
152
153#[cfg(test)]
154mod tests;