laminar_core/alloc/
guard.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum PriorityClass {
9 EventProcessing,
11 BackgroundIo,
13 Control,
15}
16
17#[cfg(debug_assertions)]
18std::thread_local! {
19 static CURRENT_PRIORITY: std::cell::Cell<Option<PriorityClass>> = const { std::cell::Cell::new(None) };
20}
21
22pub struct PriorityGuard {
29 #[cfg(debug_assertions)]
30 previous: Option<PriorityClass>,
31}
32
33impl PriorityGuard {
34 #[inline]
36 #[must_use]
37 pub fn enter(#[allow(unused_variables)] class: PriorityClass) -> Self {
38 #[cfg(debug_assertions)]
39 {
40 let previous = CURRENT_PRIORITY.with(|c| {
41 let prev = c.get();
42 c.set(Some(class));
43 prev
44 });
45 Self { previous }
46 }
47 #[cfg(not(debug_assertions))]
48 {
49 Self {}
50 }
51 }
52
53 #[inline]
55 #[must_use]
56 pub fn current() -> Option<PriorityClass> {
57 #[cfg(debug_assertions)]
58 {
59 CURRENT_PRIORITY.with(std::cell::Cell::get)
60 }
61 #[cfg(not(debug_assertions))]
62 {
63 None
64 }
65 }
66}
67
68impl Drop for PriorityGuard {
69 #[inline]
70 fn drop(&mut self) {
71 #[cfg(debug_assertions)]
72 {
73 CURRENT_PRIORITY.with(|c| c.set(self.previous));
74 }
75 }
76}
77
78impl std::fmt::Debug for PriorityGuard {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 f.debug_struct("PriorityGuard").finish()
81 }
82}
83
84#[macro_export]
89macro_rules! debug_assert_priority {
90 ($class:expr) => {
91 #[cfg(debug_assertions)]
92 {
93 let current = $crate::alloc::PriorityGuard::current();
94 debug_assert!(
95 current == Some($class),
96 "priority class mismatch: expected {:?}, got {:?}",
97 $class,
98 current,
99 );
100 }
101 };
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn test_priority_guard_enter_exit() {
110 assert_eq!(PriorityGuard::current(), None);
111
112 {
113 let _guard = PriorityGuard::enter(PriorityClass::EventProcessing);
114 assert_eq!(
115 PriorityGuard::current(),
116 Some(PriorityClass::EventProcessing)
117 );
118 }
119
120 assert_eq!(PriorityGuard::current(), None);
121 }
122
123 #[test]
124 fn test_priority_guard_nesting() {
125 let _outer = PriorityGuard::enter(PriorityClass::EventProcessing);
126 assert_eq!(
127 PriorityGuard::current(),
128 Some(PriorityClass::EventProcessing)
129 );
130
131 {
132 let _inner = PriorityGuard::enter(PriorityClass::BackgroundIo);
133 assert_eq!(PriorityGuard::current(), Some(PriorityClass::BackgroundIo));
134 }
135
136 assert_eq!(
137 PriorityGuard::current(),
138 Some(PriorityClass::EventProcessing)
139 );
140 }
141
142 #[test]
143 fn test_debug_assert_priority() {
144 let _guard = PriorityGuard::enter(PriorityClass::Control);
145 debug_assert_priority!(PriorityClass::Control);
146 }
147}