ferroui_base/threading/
dispatcher_priority.rs1use std::fmt;
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
6pub struct DispatcherPriority {
7 value: i32,
8}
9
10impl DispatcherPriority {
11 const fn new(value: i32) -> Self {
12 Self { value }
13 }
14
15 #[inline]
17 pub const fn value(self) -> i32 {
18 self.value
19 }
20
21 pub const DEFAULT: Self = Self::new(0);
23
24 pub(crate) const MINIMUM_FOREGROUND_PRIORITY: Self = Self::DEFAULT;
25
26 pub const INPUT: Self = Self::new(Self::DEFAULT.value - 1);
28
29 pub const BACKGROUND: Self = Self::new(Self::INPUT.value - 1);
31
32 pub const CONTEXT_IDLE: Self = Self::new(Self::BACKGROUND.value - 1);
34
35 pub const APPLICATION_IDLE: Self = Self::new(Self::CONTEXT_IDLE.value - 1);
37
38 pub const SYSTEM_IDLE: Self = Self::new(Self::APPLICATION_IDLE.value - 1);
40
41 pub(crate) const MINIMUM_ACTIVE_VALUE: Self = Self::new(Self::SYSTEM_IDLE.value);
43
44 pub const INACTIVE: Self = Self::new(Self::MINIMUM_ACTIVE_VALUE.value - 1);
46
47 pub(crate) const MIN_VALUE: Self = Self::new(Self::INACTIVE.value);
49
50 pub const INVALID: Self = Self::new(Self::MINIMUM_ACTIVE_VALUE.value - 2);
52
53 pub const LOADED: Self = Self::new(Self::DEFAULT.value + 1);
55
56 pub const UI_THREAD_RENDER: Self = Self::new(Self::LOADED.value + 1);
59
60 pub const AFTER_RENDER: Self = Self::new(Self::UI_THREAD_RENDER.value + 1);
64
65 pub const RENDER: Self = Self::new(Self::AFTER_RENDER.value + 1);
67
68 pub const BEFORE_RENDER: Self = Self::new(Self::RENDER.value + 1);
71
72 pub const ASYNC_RENDER_TARGET_RESIZE: Self = Self::new(Self::BEFORE_RENDER.value + 1);
75
76 #[deprecated(note = "WPF compatibility")]
78 pub const DATA_BIND: Self = Self::new(Self::ASYNC_RENDER_TARGET_RESIZE.value + 1);
79
80 pub const NORMAL: Self = Self::new(Self::ASYNC_RENDER_TARGET_RESIZE.value + 2);
82
83 pub const SEND: Self = Self::new(Self::NORMAL.value + 1);
85
86 pub const MAX_VALUE: Self = Self::SEND;
88
89 pub fn from_value(value: i32) -> Self {
95 match Self::try_from(value) {
96 Ok(priority) => priority,
97 Err(_) => panic!("value: specified argument was out of the range of valid values"),
98 }
99 }
100
101 pub fn validate(priority: DispatcherPriority, parameter_name: &str) {
106 if priority < Self::INACTIVE || priority > Self::MAX_VALUE {
107 panic!("Invalid DispatcherPriority value (parameter '{parameter_name}')");
108 }
109 }
110}
111
112impl Default for DispatcherPriority {
113 fn default() -> Self {
114 Self::DEFAULT
115 }
116}
117
118#[derive(Clone, Copy, Debug, PartialEq, Eq)]
121pub struct DispatcherPriorityOutOfRangeError(pub i32);
122
123impl fmt::Display for DispatcherPriorityOutOfRangeError {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(f, "{} is not a valid dispatcher priority", self.0)
126 }
127}
128
129impl std::error::Error for DispatcherPriorityOutOfRangeError {}
130
131impl TryFrom<i32> for DispatcherPriority {
132 type Error = DispatcherPriorityOutOfRangeError;
133
134 fn try_from(value: i32) -> Result<Self, Self::Error> {
135 if !(Self::MIN_VALUE.value..=Self::MAX_VALUE.value).contains(&value) {
136 Err(DispatcherPriorityOutOfRangeError(value))
137 } else {
138 Ok(Self::new(value))
139 }
140 }
141}
142
143impl From<DispatcherPriority> for i32 {
144 fn from(priority: DispatcherPriority) -> i32 {
145 priority.value
146 }
147}
148
149#[allow(deprecated)]
150impl fmt::Display for DispatcherPriority {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 let name = match *self {
153 Self::INVALID => "Invalid",
154 Self::INACTIVE => "Inactive",
155 Self::SYSTEM_IDLE => "SystemIdle",
156 Self::CONTEXT_IDLE => "ContextIdle",
157 Self::APPLICATION_IDLE => "ApplicationIdle",
158 Self::BACKGROUND => "Background",
159 Self::INPUT => "Input",
160 Self::DEFAULT => "Default",
161 Self::LOADED => "Loaded",
162 Self::UI_THREAD_RENDER => "UiThreadRender",
163 Self::AFTER_RENDER => "AfterRender",
164 Self::RENDER => "Render",
165 Self::BEFORE_RENDER => "BeforeRender",
166 Self::ASYNC_RENDER_TARGET_RESIZE => "AsyncRenderTargetResize",
167 Self::DATA_BIND => "DataBind",
168 Self::NORMAL => "Normal",
169 Self::SEND => "Send",
170 _ => return write!(f, "{}", self.value),
171 };
172 f.write_str(name)
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 #[allow(deprecated)]
182 fn values_match_the_documented_ordering() {
183 assert_eq!(DispatcherPriority::INVALID.value(), -7);
184 assert_eq!(DispatcherPriority::INACTIVE.value(), -6);
185 assert_eq!(DispatcherPriority::SYSTEM_IDLE.value(), -5);
186 assert_eq!(DispatcherPriority::APPLICATION_IDLE.value(), -4);
187 assert_eq!(DispatcherPriority::CONTEXT_IDLE.value(), -3);
188 assert_eq!(DispatcherPriority::BACKGROUND.value(), -2);
189 assert_eq!(DispatcherPriority::INPUT.value(), -1);
190 assert_eq!(DispatcherPriority::DEFAULT.value(), 0);
191 assert_eq!(DispatcherPriority::LOADED.value(), 1);
192 assert_eq!(DispatcherPriority::UI_THREAD_RENDER.value(), 2);
193 assert_eq!(DispatcherPriority::AFTER_RENDER.value(), 3);
194 assert_eq!(DispatcherPriority::RENDER.value(), 4);
195 assert_eq!(DispatcherPriority::BEFORE_RENDER.value(), 5);
196 assert_eq!(DispatcherPriority::ASYNC_RENDER_TARGET_RESIZE.value(), 6);
197 assert_eq!(DispatcherPriority::DATA_BIND.value(), 7);
198 assert_eq!(DispatcherPriority::NORMAL.value(), 8);
199 assert_eq!(DispatcherPriority::SEND.value(), 9);
200 assert_eq!(DispatcherPriority::default(), DispatcherPriority::DEFAULT);
201 assert!(DispatcherPriority::RENDER > DispatcherPriority::INPUT);
202 }
203
204 #[test]
205 fn from_value_validates_the_range() {
206 assert_eq!(DispatcherPriority::try_from(4), Ok(DispatcherPriority::RENDER));
207 assert!(DispatcherPriority::try_from(-7).is_err());
208 assert!(DispatcherPriority::try_from(10).is_err());
209 assert_eq!(i32::from(DispatcherPriority::SEND), 9);
210 }
211
212 #[test]
213 fn display_uses_the_priority_name() {
214 assert_eq!(DispatcherPriority::RENDER.to_string(), "Render");
215 assert_eq!(DispatcherPriority::INVALID.to_string(), "Invalid");
216 assert_eq!(DispatcherPriority::UI_THREAD_RENDER.to_string(), "UiThreadRender");
217 }
218
219 #[test]
220 #[should_panic(expected = "Invalid DispatcherPriority value")]
221 fn validate_rejects_invalid() {
222 DispatcherPriority::validate(DispatcherPriority::INVALID, "priority");
223 }
224}