1use std::{mem, pin, task};
2
3use dope::core::driver::schedule::clock::timer;
4use dope_fiber::context;
5use o3::base::time::Positive;
6
7#[derive(Clone, Copy, Eq, PartialEq, Debug)]
9pub enum RequestPhase {
10 Admission,
11 Response,
12 Settlement,
13 Lease,
14 Contention,
15}
16
17#[derive(Clone, Copy, Eq, PartialEq, Debug)]
18pub struct Elapsed {
19 phase: RequestPhase,
20}
21
22impl Elapsed {
23 pub const fn new(phase: RequestPhase) -> Self {
24 Self { phase }
25 }
26
27 pub const fn phase(self) -> RequestPhase {
28 self.phase
29 }
30}
31
32#[derive(Clone, Copy)]
34pub struct Source<'d> {
35 timer: timer::Timer<'d>,
36 window: Positive,
37}
38
39impl<'d> Source<'d> {
40 pub const fn new(timer: timer::Timer<'d>, window: Positive) -> Self {
41 Self { timer, window }
42 }
43
44 #[inline]
45 pub fn guard(self) -> Result<Guard<'d>, timer::Exhausted> {
46 Ok(Guard {
47 state: GuardState::Live {
48 alarm: self.timer.try_alarm()?,
49 window: Some(self.window),
50 },
51 })
52 }
53
54 pub const fn into_parts(self) -> (timer::Timer<'d>, Positive) {
55 (self.timer, self.window)
56 }
57}
58
59pub struct Guard<'d> {
61 state: GuardState<'d>,
62}
63
64enum GuardState<'d> {
65 Live {
66 alarm: timer::Alarm<'d>,
67 window: Option<Positive>,
68 },
69 Elapsed,
70 Complete,
71}
72
73impl<'d> Guard<'d> {
74 pub fn poll_expired(
75 self: pin::Pin<&mut Self>,
76 mut ctx: pin::Pin<&mut context::Context<'_, 'd>>,
77 phase: RequestPhase,
78 ) -> task::Poll<Elapsed> {
79 let state = &mut self.get_mut().state;
80 let (alarm, window) = match state {
81 GuardState::Live { alarm, window } => (alarm, window),
82 GuardState::Elapsed => return task::Poll::Ready(Elapsed::new(phase)),
83 GuardState::Complete => return task::Poll::Pending,
84 };
85 let wake = ctx.as_ref().completion();
86 let now = ctx.as_mut().driver().driver_ref().clock().now();
87 let expired = match window.take() {
88 Some(duration) => alarm.arm_and_poll(now.clamp_add(duration), now, wake),
89 None => alarm.poll(now, wake),
90 };
91 if expired.is_ready() {
92 *state = GuardState::Elapsed;
93 task::Poll::Ready(Elapsed::new(phase))
94 } else {
95 task::Poll::Pending
96 }
97 }
98
99 pub fn complete(&mut self) {
100 self.state = GuardState::Complete;
101 }
102}
103
104const _: () = {
105 const LIVE: usize = mem::size_of::<timer::Alarm<'static>>() + mem::size_of::<Positive>();
106
107 assert!(mem::size_of::<Guard<'static>>() == LIVE);
108 assert!(mem::size_of::<Option<Guard<'static>>>() == LIVE);
109 assert!(mem::size_of::<Result<Guard<'static>, timer::Exhausted>>() == LIVE);
110};