1use core::fmt::Debug;
2
3#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5#[repr(u8)]
6pub enum Signal {
7 Hangup = 0,
9 Interrupt,
11 Quit,
13 IllegalInstruction,
15 Trap,
17 Abort,
19 BusError,
21 FloatingPointException,
23 Kill,
25 User1,
27 SegmentationFault,
29 User2,
31 BrokenPipe,
33 Alarm,
35 Termination,
37 StackFault,
39 Child,
41 Continue,
43 Stop,
45 TerminalStop,
47 TerminalInput,
49 TerminalOutput,
51 Urgent,
53 CpuTimeLimitExceeded,
55 FileSizeLimitExceeded,
57 VirtualAlarm,
59 ProfilingTimerExpired,
61 WindowResize,
63 IoPossible,
65 PowerFailure,
67 BadSystemCall,
69}
70
71impl Signal {
72 pub const FIRST: Self = Self::Hangup;
73 pub const LAST: Self = Self::BadSystemCall;
74
75 pub const fn get_discriminant(&self) -> u8 {
76 *self as u8
77 }
78}
79
80#[derive(Debug, Copy, Clone)]
81#[repr(transparent)]
82pub struct SignalAccumulator {
83 accumulator: u32,
84}
85
86impl Default for SignalAccumulator {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92impl SignalAccumulator {
93 pub const fn new() -> Self {
94 Self { accumulator: 0 }
95 }
96
97 pub const fn send(&mut self, signal: Signal) {
98 self.accumulator |= 1 << signal as u32;
99 }
100
101 pub const fn clear(&mut self, signal: Signal) {
102 self.accumulator &= !(1 << signal as u32);
103 }
104
105 pub const fn has_signal(&self, signal: Signal) -> bool {
106 self.accumulator & (1 << signal as u32) != 0
107 }
108
109 pub fn peek(&self) -> Option<Signal> {
110 for bit in Signal::FIRST as u8..=Signal::LAST as u8 {
111 let signal = unsafe { core::mem::transmute::<u8, Signal>(bit) };
112
113 if self.has_signal(signal) {
114 return Some(signal);
115 }
116 }
117
118 None
119 }
120
121 pub fn pop(&mut self) -> Option<Signal> {
122 if let Some(signal) = self.peek() {
123 self.clear(signal);
124
125 Some(signal)
126 } else {
127 None
128 }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn test_send_and_has_signal() {
138 let mut acc = SignalAccumulator::new();
139 acc.send(Signal::Interrupt);
140 assert!(acc.has_signal(Signal::Interrupt));
141 }
142
143 #[test]
144 fn test_clear_signal() {
145 let mut acc = SignalAccumulator::new();
146 acc.send(Signal::Quit);
147 acc.clear(Signal::Quit);
148 assert!(!acc.has_signal(Signal::Quit));
149 }
150
151 #[test]
152 fn test_peek_and_pop() {
153 let mut acc = SignalAccumulator::new();
154 acc.send(Signal::Hangup);
155 acc.send(Signal::User1);
156 assert_eq!(acc.peek(), Some(Signal::Hangup));
157 assert_eq!(acc.pop(), Some(Signal::Hangup));
158 assert_eq!(acc.peek(), Some(Signal::User1));
159 assert_eq!(acc.pop(), Some(Signal::User1));
160 assert_eq!(acc.pop(), None);
161 }
162
163 #[test]
164 fn test_signal_discriminant() {
165 assert_eq!(
166 Signal::PowerFailure.get_discriminant(),
167 Signal::PowerFailure as u8
168 );
169 }
170}