1use std::{cell, 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 pub fn guard(self) -> Result<Guard<'d>, timer::Exhausted> {
45 Ok(Guard {
46 alarm: self.timer.try_alarm()?,
47 window: self.window,
48 state: cell::Cell::new(GuardState::Fresh),
49 })
50 }
51
52 pub const fn into_parts(self) -> (timer::Timer<'d>, Positive) {
53 (self.timer, self.window)
54 }
55}
56
57pub struct Guard<'d> {
59 alarm: timer::Alarm<'d>,
60 window: Positive,
61 state: cell::Cell<GuardState>,
62}
63
64#[derive(Clone, Copy)]
65#[repr(u8)]
66enum GuardState {
67 Fresh,
68 Armed,
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 this = self.get_mut();
80 match this.state.get() {
81 GuardState::Elapsed => return task::Poll::Ready(Elapsed::new(phase)),
82 GuardState::Complete => return task::Poll::Pending,
83 GuardState::Fresh => {
84 let wake = ctx.as_ref().completion();
85 let now = ctx.as_mut().driver().driver_ref().clock().now();
86 let due = now.clamp_add(this.window);
87 this.state.set(GuardState::Armed);
88 this.alarm.arm(due, wake);
89 return task::Poll::Pending;
90 }
91 GuardState::Armed => {}
92 }
93 let wake = ctx.as_ref().completion();
94 let now = ctx.as_mut().driver().driver_ref().clock().now();
95 if this.alarm.poll(now, wake).is_ready() {
96 this.state.set(GuardState::Elapsed);
97 task::Poll::Ready(Elapsed::new(phase))
98 } else {
99 task::Poll::Pending
100 }
101 }
102
103 pub fn complete(&self) {
104 self.alarm.clear();
105 self.state.set(GuardState::Complete);
106 }
107}
108
109const _: () = {
110 assert!(mem::size_of::<GuardState>() == 1);
111 assert!(mem::size_of::<cell::Cell<GuardState>>() == mem::size_of::<GuardState>());
112 assert!(mem::align_of::<cell::Cell<GuardState>>() == mem::align_of::<GuardState>());
113};