1use slotmap::{new_key_type, SlotMap};
9use std::cmp::Reverse;
10use std::collections::{BinaryHeap, HashMap};
11use std::io;
12use std::os::unix::io::RawFd;
13use thiserror::Error;
14
15pub const E_READ: u32 = 0x1;
21
22pub const E_WRITE: u32 = 0x2;
24
25pub const EPSILON: f64 = 1.0e-3;
27
28pub const FANOUT_UNLIMITED: i32 = -1;
30
31#[derive(Error, Debug)]
37pub enum EngineError {
38 #[error("Operation aborted (kill={kill})")]
40 Abort { kill: bool },
41
42 #[error("Operation timed out")]
44 Timeout,
45
46 #[error("Illegal operation: {0}")]
48 IllegalOperation(String),
49
50 #[error("Engine is already running")]
52 AlreadyRunning,
53
54 #[error("Not supported: {0}")]
56 NotSupported(String),
57
58 #[error("I/O error: {0}")]
60 Io(#[from] io::Error),
61}
62
63new_key_type! { pub struct TimerId; }
68
69#[derive(Debug, Clone)]
78pub struct EngineBaseTimer {
79 fire_delay: f64,
80 interval: f64,
81 autoclose: bool,
82}
83
84impl EngineBaseTimer {
85 pub fn new(fire_delay: f64, interval: f64, autoclose: bool) -> Self {
92 Self {
93 fire_delay,
94 interval,
95 autoclose,
96 }
97 }
98
99 pub fn invalidate(&mut self) {
101 self.fire_delay = -1.0;
102 }
103
104 pub fn is_valid(&self) -> bool {
106 self.fire_delay >= 0.0
107 }
108
109 pub fn set_nextfire(&mut self, fire_delay: f64, interval: f64) {
115 self.fire_delay = fire_delay;
116 self.interval = interval;
117 }
118
119 pub fn fire_delay(&self) -> f64 {
121 self.fire_delay
122 }
123
124 pub fn interval(&self) -> f64 {
126 self.interval
127 }
128
129 pub fn autoclose(&self) -> bool {
131 self.autoclose
132 }
133}
134
135#[derive(Debug, Clone, PartialEq)]
141struct TimerEntry {
142 fire_date: f64,
143 timer_id: TimerId,
144 armed: bool,
145}
146
147impl Eq for TimerEntry {}
148
149impl Ord for TimerEntry {
150 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
151 self.fire_date
153 .partial_cmp(&other.fire_date)
154 .unwrap_or(std::cmp::Ordering::Equal)
155 .then_with(|| self.timer_id.cmp(&other.timer_id))
156 }
157}
158
159impl PartialOrd for TimerEntry {
160 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
161 Some(self.cmp(other))
162 }
163}
164
165#[derive(Debug)]
170pub struct TimerQueue {
171 timers: BinaryHeap<Reverse<TimerEntry>>,
172 timer_data: SlotMap<TimerId, EngineBaseTimer>,
173 armed_count: usize,
174 current_time: f64,
175}
176
177impl TimerQueue {
178 pub fn new() -> Self {
180 Self {
181 timers: BinaryHeap::new(),
182 timer_data: SlotMap::with_capacity_and_key(16),
183 armed_count: 0,
184 current_time: 0.0,
185 }
186 }
187
188 pub fn schedule(&mut self, timer_id: TimerId) {
193 if let Some(timer) = self.timer_data.get(timer_id) {
194 if timer.fire_delay >= 0.0 {
195 let fire_date = self.current_time + timer.fire_delay;
196 let entry = TimerEntry {
197 fire_date,
198 timer_id,
199 armed: true,
200 };
201 self.timers.push(Reverse(entry));
202 self.armed_count += 1;
203 }
204 }
205 }
206
207 pub fn reschedule(&mut self, timer_id: TimerId) {
212 self.invalidate(timer_id);
214 self.schedule(timer_id);
215 }
216
217 pub fn invalidate(&mut self, timer_id: TimerId) {
222 let mut found = false;
224 let mut new_heap = BinaryHeap::new();
225 for Reverse(entry) in self.timers.drain() {
226 if entry.timer_id == timer_id {
227 found = true;
228 if let Some(timer) = self.timer_data.get_mut(timer_id) {
230 timer.invalidate();
231 }
232 } else {
233 new_heap.push(Reverse(entry));
234 }
235 }
236 self.timers = new_heap;
237 if found {
238 self.armed_count = self.armed_count.saturating_sub(1);
239 }
240 }
241
242 pub fn fire_expired(&mut self) -> Vec<(TimerId, bool)> {
246 let mut fired = Vec::new();
247 let now = self.current_time;
248
249 while let Some(Reverse(entry)) = self.timers.peek() {
251 if entry.fire_date > now + EPSILON {
252 break;
253 }
254
255 let entry = self.timers.pop().unwrap().0;
256 let timer_id = entry.timer_id;
257
258 if let Some(timer) = self.timer_data.get(timer_id) {
259 if entry.armed && timer.fire_delay >= 0.0 {
260 fired.push((timer_id, timer.autoclose));
261
262 if timer.interval >= 0.0 {
264 let new_fire_date = now + timer.interval;
265 let new_entry = TimerEntry {
266 fire_date: new_fire_date,
267 timer_id,
268 armed: true,
269 };
270 self.timers.push(Reverse(new_entry));
271 } else {
272 if let Some(t) = self.timer_data.get_mut(timer_id) {
274 t.invalidate();
275 }
276 self.armed_count = self.armed_count.saturating_sub(1);
277 }
278 }
279 }
280 }
281
282 fired
283 }
284
285 pub fn nextfire_delay(&self) -> Option<f64> {
289 if let Some(Reverse(entry)) = self.timers.peek() {
290 let delay = entry.fire_date - self.current_time;
291 if delay > EPSILON {
292 Some(delay)
293 } else {
294 Some(0.0)
295 }
296 } else {
297 None
298 }
299 }
300
301 pub fn clear(&mut self) {
303 self.timers.clear();
304 self.timer_data.clear();
305 self.armed_count = 0;
306 }
307
308 pub fn add_timer(&mut self, timer: EngineBaseTimer) -> TimerId {
312 let timer_id = self.timer_data.insert(timer);
313 timer_id
314 }
315
316 pub fn remove_timer(&mut self, timer_id: TimerId) {
318 self.invalidate(timer_id);
319 self.timer_data.remove(timer_id);
320 }
321
322 pub fn armed_count(&self) -> usize {
324 self.armed_count
325 }
326
327 pub fn update_time(&mut self, time: f64) {
329 self.current_time = time;
330 }
331
332 pub fn is_valid(&self, timer_id: TimerId) -> bool {
334 self.timer_data
335 .get(timer_id)
336 .map(|t| t.is_valid())
337 .unwrap_or(false)
338 }
339}
340
341impl Default for TimerQueue {
342 fn default() -> Self {
343 Self::new()
344 }
345}
346
347pub struct EngineTimer {
356 base: EngineBaseTimer,
357 handler: Box<dyn FnMut() + Send>,
358}
359
360impl EngineTimer {
361 pub fn new(
369 fire_delay: f64,
370 interval: f64,
371 autoclose: bool,
372 handler: impl FnMut() + Send + 'static,
373 ) -> Self {
374 Self {
375 base: EngineBaseTimer::new(fire_delay, interval, autoclose),
376 handler: Box::new(handler),
377 }
378 }
379
380 pub fn fire(&mut self) {
382 (self.handler)();
383 }
384
385 pub fn base(&self) -> &EngineBaseTimer {
387 &self.base
388 }
389
390 pub fn base_mut(&mut self) -> &mut EngineBaseTimer {
392 &mut self.base
393 }
394}
395
396impl std::fmt::Debug for EngineTimer {
397 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
398 f.debug_struct("EngineTimer")
399 .field("base", &self.base)
400 .field("handler", &"<fn>")
401 .finish()
402 }
403}
404
405pub trait EngineClient: Send {
414 fn start(&mut self) -> io::Result<()>;
416
417 fn close(&mut self, abort: bool, timeout: bool);
423
424 fn fd(&self) -> Option<RawFd>;
426
427 fn events(&self) -> u32;
429
430 fn is_delayable(&self) -> bool;
432
433 fn is_registered(&self) -> bool;
435
436 fn set_registered(&mut self, val: bool);
438
439 fn autoclose(&self) -> bool;
441
442 fn handle_read(&mut self) -> io::Result<usize> {
445 Ok(0)
446 }
447
448 fn handle_write(&mut self) -> io::Result<usize> {
451 Ok(0)
452 }
453}
454
455new_key_type! { pub struct ClientId; }
460
461pub trait PollBackend: Send + Sync {
470 fn register(&mut self, fd: RawFd, events: u32, client_id: ClientId) -> io::Result<()>;
477
478 fn modify(&mut self, fd: RawFd, events: u32, client_id: ClientId) -> io::Result<()>;
480
481 fn unregister(&mut self, fd: RawFd) -> io::Result<()>;
483
484 fn wait(&mut self, timeout: Option<f64>) -> io::Result<Vec<(RawFd, u32, ClientId)>>;
488
489 fn name(&self) -> &str;
491}
492
493pub struct Engine<B: PollBackend> {
514 clients: SlotMap<ClientId, Box<dyn EngineClient>>,
515 timerq: TimerQueue,
516 reg_clifds: HashMap<RawFd, ClientId>,
517 poll_backend: B,
518 fanout: usize,
519 running: bool,
520 exited: bool,
521 evlooprefcnt: i32,
522}
523
524impl<B: PollBackend> Engine<B> {
525 pub fn with_backend(backend: B, fanout: usize) -> Self {
531 Self {
532 clients: SlotMap::with_key(),
533 timerq: TimerQueue::new(),
534 reg_clifds: HashMap::new(),
535 poll_backend: backend,
536 fanout,
537 running: false,
538 exited: false,
539 evlooprefcnt: 0,
540 }
541 }
542
543 pub fn add_timer(&mut self, timer: EngineBaseTimer) -> TimerId {
548 let timer_id = self.timerq.add_timer(timer);
549 self.timerq.schedule(timer_id);
550 timer_id
551 }
552
553 pub fn remove_timer(&mut self, id: TimerId) {
558 self.timerq.remove_timer(id);
559 }
560
561 pub fn fire_timers(&mut self) {
563 let _fired = self.timerq.fire_expired();
564 }
568
569 pub fn run(&mut self, timeout: Option<f64>) -> Result<(), EngineError> {
579 if self.running {
580 return Err(EngineError::AlreadyRunning);
581 }
582
583 self.running = true;
584 self.exited = false;
585
586 let start_time = self.timerq.current_time;
587 let max_time = timeout.map(|t| start_time + t);
588
589 while self.running {
590 self.timerq.update_time(self.timerq.current_time + 0.001);
592
593 self.fire_timers();
595
596 if !self.running {
598 break;
599 }
600
601 let next_timer_delay = self.timerq.nextfire_delay();
603
604 let poll_timeout = match (max_time, next_timer_delay) {
606 (Some(max), Some(timer_delay)) => {
607 let remaining = max - self.timerq.current_time;
608 if remaining <= EPSILON {
609 self.running = false;
610 self.exited = true;
611 return Err(EngineError::Timeout);
612 }
613 Some(if remaining < timer_delay {
615 remaining
616 } else {
617 timer_delay
618 })
619 }
620 (Some(max), None) => {
621 let remaining = max - self.timerq.current_time;
622 if remaining <= EPSILON {
623 self.running = false;
624 self.exited = true;
625 return Err(EngineError::Timeout);
626 }
627 Some(remaining)
628 }
629 (None, Some(timer_delay)) => Some(timer_delay),
630 (None, None) => None,
631 };
632
633 let events = match self.poll_backend.wait(poll_timeout.map(|t| t.max(0.0))) {
635 Ok(events) => events,
636 Err(err) if err.kind() == io::ErrorKind::Interrupted => {
637 continue;
640 }
641 Err(err) => {
642 self.running = false;
646 self.exited = true;
647 return Err(EngineError::Io(err));
648 }
649 };
650
651 for (_fd, events_mask, client_id) in events {
653 if let Some(client) = self.clients.get_mut(client_id) {
654 if events_mask & E_READ != 0 {
655 let _ = client.handle_read();
656 }
657 if events_mask & E_WRITE != 0 {
658 let _ = client.handle_write();
659 }
660 }
661 }
662
663 if let Some(max) = max_time {
665 if self.timerq.current_time >= max {
666 self.running = false;
667 self.exited = true;
668 return Err(EngineError::Timeout);
669 }
670 }
671 }
672
673 self.exited = true;
674 self.running = false;
675 Ok(())
676 }
677
678 pub fn abort(&mut self, kill: bool) {
683 if kill {
684 for (_, client) in self.clients.iter_mut() {
686 client.close(true, false);
687 }
688 }
689 self.running = false;
690 }
691
692 pub fn is_running(&self) -> bool {
694 self.running
695 }
696
697 pub fn exited(&self) -> bool {
699 self.exited
700 }
701
702 pub fn add_client(&mut self, client: Box<dyn EngineClient>) -> Result<ClientId, EngineError> {
707 let client_id = self.clients.insert(client);
708
709 if let Some(client) = self.clients.get(client_id) {
710 if let Some(fd) = client.fd() {
711 if fd >= 0 {
712 let events = client.events();
713 self.poll_backend.register(fd, events, client_id)?;
714 self.reg_clifds.insert(fd, client_id);
715 }
716 }
717 }
718
719 Ok(client_id)
720 }
721
722 pub fn remove_client(&mut self, id: ClientId) {
727 if let Some(client) = self.clients.get(id) {
728 if let Some(fd) = client.fd() {
729 if fd >= 0 {
730 let _ = self.poll_backend.unregister(fd);
731 self.reg_clifds.remove(&fd);
732 }
733 }
734 }
735 self.clients.remove(id);
736 }
737
738 pub fn fanout(&self) -> usize {
740 self.fanout
741 }
742
743 pub fn update_client_events(&mut self, client_id: ClientId) -> Result<(), EngineError> {
745 if let Some(client) = self.clients.get(client_id) {
746 if let Some(fd) = client.fd() {
747 if fd >= 0 {
748 let events = client.events();
749 if self.reg_clifds.contains_key(&fd) {
750 self.poll_backend.modify(fd, events, client_id)?;
751 } else {
752 self.poll_backend.register(fd, events, client_id)?;
753 self.reg_clifds.insert(fd, client_id);
754 }
755 }
756 }
757 }
758 Ok(())
759 }
760
761 pub fn stop(&mut self) {
763 self.running = false;
764 }
765
766 pub fn evloop_acquire(&mut self) {
769 self.evlooprefcnt += 1;
770 }
771
772 pub fn evloop_release(&mut self) {
775 self.evlooprefcnt -= 1;
776 if self.evlooprefcnt <= 0 {
777 self.running = false;
778 }
779 }
780
781 pub fn client_count(&self) -> usize {
783 self.clients.len()
784 }
785
786 pub fn timerq(&self) -> &TimerQueue {
788 &self.timerq
789 }
790
791 pub fn timerq_mut(&mut self) -> &mut TimerQueue {
793 &mut self.timerq
794 }
795
796 pub fn start_all_clients(&mut self) -> io::Result<()> {
798 let ids: Vec<ClientId> = self.clients.keys().collect();
799 for id in ids {
800 if let Some(client) = self.clients.get_mut(id) {
801 client.start()?;
802 }
803 }
804 Ok(())
805 }
806}
807
808#[derive(Debug, Default)]
816pub struct NullBackend;
817
818impl PollBackend for NullBackend {
819 fn register(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
820 Ok(())
821 }
822
823 fn modify(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
824 Ok(())
825 }
826
827 fn unregister(&mut self, _fd: RawFd) -> io::Result<()> {
828 Ok(())
829 }
830
831 fn wait(&mut self, _timeout: Option<f64>) -> io::Result<Vec<(RawFd, u32, ClientId)>> {
832 Ok(Vec::new())
833 }
834
835 fn name(&self) -> &str {
836 "null"
837 }
838}
839
840#[cfg(test)]
845mod tests {
846 use super::*;
847
848 #[test]
849 fn test_engine_constants() {
850 assert_eq!(E_READ, 0x1);
851 assert_eq!(E_WRITE, 0x2);
852 assert!((EPSILON - 1.0e-3).abs() < EPSILON);
853 assert_eq!(FANOUT_UNLIMITED, -1);
854 }
855
856 #[test]
857 fn test_engine_base_timer() {
858 let mut timer = EngineBaseTimer::new(5.0, -1.0, false);
859 assert!(timer.is_valid());
860 assert_eq!(timer.fire_delay(), 5.0);
861 assert_eq!(timer.interval(), -1.0);
862
863 timer.invalidate();
864 assert!(!timer.is_valid());
865 assert_eq!(timer.fire_delay(), -1.0);
866
867 timer.set_nextfire(10.0, 2.0);
868 assert!(timer.is_valid());
869 assert_eq!(timer.fire_delay(), 10.0);
870 assert_eq!(timer.interval(), 2.0);
871 }
872
873 #[test]
874 fn test_timer_queue_scheduling() {
875 let mut timerq = TimerQueue::new();
876
877 let timer1 = timerq.add_timer(EngineBaseTimer::new(1.0, -1.0, false));
879 let timer2 = timerq.add_timer(EngineBaseTimer::new(2.0, -1.0, false));
880 let timer3 = timerq.add_timer(EngineBaseTimer::new(0.5, -1.0, false));
881
882 timerq.schedule(timer1);
884 timerq.schedule(timer2);
885 timerq.schedule(timer3);
886
887 assert_eq!(timerq.armed_count(), 3);
889
890 let delay = timerq.nextfire_delay();
892 assert!(delay.is_some());
893 assert!((delay.unwrap() - 0.5).abs() < EPSILON);
894 }
895
896 #[test]
897 fn test_timer_queue_firing() {
898 let mut timerq = TimerQueue::new();
899
900 let timer1 = timerq.add_timer(EngineBaseTimer::new(0.1, -1.0, false));
902 let timer2 = timerq.add_timer(EngineBaseTimer::new(0.2, -1.0, false));
903
904 timerq.schedule(timer1);
905 timerq.schedule(timer2);
906
907 timerq.update_time(0.3);
909
910 let fired = timerq.fire_expired();
912
913 assert_eq!(fired.len(), 2);
915
916 assert!(!timerq.is_valid(timer1));
918 assert!(!timerq.is_valid(timer2));
919 }
920
921 #[test]
922 fn test_timer_queue_invalidation() {
923 let mut timerq = TimerQueue::new();
924
925 let timer1 = timerq.add_timer(EngineBaseTimer::new(1.0, -1.0, false));
926 let timer2 = timerq.add_timer(EngineBaseTimer::new(2.0, -1.0, false));
927
928 timerq.schedule(timer1);
929 timerq.schedule(timer2);
930
931 timerq.invalidate(timer1);
933
934 assert_eq!(timerq.armed_count(), 1);
936
937 let delay = timerq.nextfire_delay();
939 assert!(delay.is_some());
940 assert!((delay.unwrap() - 2.0).abs() < EPSILON);
941 }
942
943 #[test]
944 fn test_timer_queue_repeat() {
945 let mut timerq = TimerQueue::new();
946
947 let timer = timerq.add_timer(EngineBaseTimer::new(0.1, 0.1, false));
949 timerq.schedule(timer);
950
951 timerq.update_time(0.15);
953 let fired = timerq.fire_expired();
954 assert_eq!(fired.len(), 1);
955
956 assert!(timerq.is_valid(timer));
958
959 timerq.update_time(0.25);
961 let fired = timerq.fire_expired();
962 assert_eq!(fired.len(), 1);
963
964 assert!(timerq.is_valid(timer));
966 }
967
968 #[test]
969 fn test_engine_error_types() {
970 let err = EngineError::Abort { kill: true };
971 assert!(matches!(err, EngineError::Abort { kill: true }));
972
973 let err = EngineError::Timeout;
974 assert!(matches!(err, EngineError::Timeout));
975
976 let err = EngineError::IllegalOperation("test".to_string());
977 assert!(matches!(err, EngineError::IllegalOperation(_)));
978
979 let err = EngineError::AlreadyRunning;
980 assert!(matches!(err, EngineError::AlreadyRunning));
981
982 let err = EngineError::NotSupported("test".to_string());
983 assert!(matches!(err, EngineError::NotSupported(_)));
984
985 let io_err = io::Error::new(io::ErrorKind::NotFound, "not found");
986 let err = EngineError::Io(io_err);
987 assert!(matches!(err, EngineError::Io(_)));
988 }
989
990 #[test]
993 fn test_null_backend_name() {
994 let nb = NullBackend;
995 assert_eq!(nb.name(), "null");
996 }
997
998 #[test]
999 fn test_null_backend_wait_returns_empty() {
1000 let mut nb = NullBackend;
1001 let events = nb.wait(Some(0.0)).unwrap();
1002 assert!(events.is_empty());
1003 }
1004
1005 #[test]
1006 fn test_null_backend_register_modify_unregister() {
1007 let mut nb = NullBackend;
1008 let mut sm: SlotMap<ClientId, ()> = SlotMap::with_key();
1011 let cid = sm.insert(());
1012 nb.register(0, E_READ, cid).unwrap();
1013 nb.modify(0, E_WRITE, cid).unwrap();
1014 nb.unregister(0).unwrap();
1015 }
1016
1017 struct DummyClient {
1020 registered: bool,
1021 started: bool,
1022 }
1023
1024 impl DummyClient {
1025 fn new() -> Self {
1026 Self {
1027 registered: false,
1028 started: false,
1029 }
1030 }
1031 }
1032
1033 impl EngineClient for DummyClient {
1034 fn start(&mut self) -> io::Result<()> {
1035 self.started = true;
1036 Ok(())
1037 }
1038
1039 fn close(&mut self, _abort: bool, _timeout: bool) {}
1040
1041 fn fd(&self) -> Option<RawFd> {
1042 None }
1044
1045 fn events(&self) -> u32 {
1046 E_READ
1047 }
1048
1049 fn is_delayable(&self) -> bool {
1050 false
1051 }
1052
1053 fn is_registered(&self) -> bool {
1054 self.registered
1055 }
1056
1057 fn set_registered(&mut self, val: bool) {
1058 self.registered = val;
1059 }
1060
1061 fn autoclose(&self) -> bool {
1062 false
1063 }
1064 }
1065
1066 #[test]
1067 fn test_engine_creation() {
1068 let engine = Engine::with_backend(NullBackend, 0);
1069 assert!(!engine.is_running());
1070 assert!(!engine.exited());
1071 assert_eq!(engine.fanout(), 0);
1072 assert_eq!(engine.client_count(), 0);
1073 }
1074
1075 #[test]
1076 fn test_engine_add_remove_client() {
1077 let mut engine = Engine::with_backend(NullBackend, 0);
1078 let cid = engine.add_client(Box::new(DummyClient::new())).unwrap();
1079 assert_eq!(engine.client_count(), 1);
1080 engine.remove_client(cid);
1081 assert_eq!(engine.client_count(), 0);
1082 }
1083
1084 #[test]
1085 fn test_engine_add_timer() {
1086 let mut engine = Engine::with_backend(NullBackend, 0);
1087 let tid = engine.add_timer(EngineBaseTimer::new(1.0, -1.0, false));
1088 assert!(engine.timerq().is_valid(tid));
1089 engine.remove_timer(tid);
1090 assert!(!engine.timerq().is_valid(tid));
1091 }
1092
1093 #[test]
1094 fn test_engine_fire_timers() {
1095 let mut engine = Engine::with_backend(NullBackend, 0);
1096 let tid = engine.add_timer(EngineBaseTimer::new(0.1, -1.0, false));
1097 assert!(engine.timerq().is_valid(tid));
1098 engine.timerq_mut().update_time(1.0);
1099 engine.fire_timers();
1100 assert!(!engine.timerq().is_valid(tid));
1101 }
1102
1103 #[test]
1104 fn test_engine_abort() {
1105 let mut engine = Engine::with_backend(NullBackend, 0);
1106 engine.abort(false);
1107 assert!(!engine.is_running());
1108 }
1109
1110 #[test]
1111 fn test_engine_evloop_refcnt() {
1112 let mut engine = Engine::with_backend(NullBackend, 0);
1113 engine.evloop_acquire();
1114 engine.evloop_acquire();
1115 engine.evloop_release();
1116 engine.evloop_release();
1119 assert!(!engine.is_running());
1121 }
1122
1123 #[test]
1124 fn test_engine_stop() {
1125 let mut engine = Engine::with_backend(NullBackend, 0);
1126 engine.stop();
1128 assert!(!engine.is_running());
1129 }
1130
1131 #[test]
1132 fn test_engine_start_all_clients() {
1133 let mut engine = Engine::with_backend(NullBackend, 0);
1134 engine.add_client(Box::new(DummyClient::new())).unwrap();
1135 engine.add_client(Box::new(DummyClient::new())).unwrap();
1136 engine.start_all_clients().unwrap();
1137 assert_eq!(engine.client_count(), 2);
1138 }
1139
1140 #[test]
1141 fn test_engine_update_client_events() {
1142 let mut engine = Engine::with_backend(NullBackend, 0);
1143 let cid = engine.add_client(Box::new(DummyClient::new())).unwrap();
1144 engine.update_client_events(cid).unwrap();
1146 }
1147
1148 struct FailBackend {
1158 errno: i32,
1159 wait_calls: usize,
1160 }
1161
1162 impl FailBackend {
1163 fn new(errno: i32) -> Self {
1164 Self {
1165 errno,
1166 wait_calls: 0,
1167 }
1168 }
1169 }
1170
1171 impl PollBackend for FailBackend {
1172 fn register(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
1173 Ok(())
1174 }
1175
1176 fn modify(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
1177 Ok(())
1178 }
1179
1180 fn unregister(&mut self, _fd: RawFd) -> io::Result<()> {
1181 Ok(())
1182 }
1183
1184 fn wait(&mut self, _timeout: Option<f64>) -> io::Result<Vec<(RawFd, u32, ClientId)>> {
1185 self.wait_calls += 1;
1186 Err(io::Error::from_raw_os_error(self.errno))
1187 }
1188
1189 fn name(&self) -> &str {
1190 "fail"
1191 }
1192 }
1193
1194 struct IntrThenFailBackend {
1197 eintr_count: usize,
1198 final_errno: i32,
1199 wait_calls: usize,
1200 }
1201
1202 impl PollBackend for IntrThenFailBackend {
1203 fn register(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
1204 Ok(())
1205 }
1206
1207 fn modify(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
1208 Ok(())
1209 }
1210
1211 fn unregister(&mut self, _fd: RawFd) -> io::Result<()> {
1212 Ok(())
1213 }
1214
1215 fn wait(&mut self, _timeout: Option<f64>) -> io::Result<Vec<(RawFd, u32, ClientId)>> {
1216 self.wait_calls += 1;
1217 if self.wait_calls <= self.eintr_count {
1218 Err(io::Error::from_raw_os_error(libc::EINTR))
1219 } else {
1220 Err(io::Error::from_raw_os_error(self.final_errno))
1221 }
1222 }
1223
1224 fn name(&self) -> &str {
1225 "intr-then-fail"
1226 }
1227 }
1228
1229 #[test]
1230 fn test_engine_poll_error_propagates() {
1231 let mut engine = Engine::with_backend(FailBackend::new(libc::EBADF), 0);
1234 engine.evloop_acquire();
1235
1236 let result = engine.run(None);
1237 match result {
1238 Err(EngineError::Io(err)) => {
1239 assert_eq!(err.raw_os_error(), Some(libc::EBADF));
1240 }
1241 other => panic!("expected EngineError::Io(EBADF), got: {:?}", other),
1242 }
1243
1244 assert!(!engine.is_running());
1246 assert!(engine.exited());
1247
1248 match engine.run(None) {
1251 Err(EngineError::Io(err)) => {
1252 assert_eq!(err.raw_os_error(), Some(libc::EBADF));
1253 }
1254 other => panic!("expected EngineError::Io(EBADF), got: {:?}", other),
1255 }
1256 }
1257
1258 #[test]
1259 fn test_engine_select_style_errors_propagate() {
1260 for errno in [libc::EINVAL, libc::EBADF, libc::ENOMEM] {
1264 let mut engine = Engine::with_backend(FailBackend::new(errno), 0);
1265 match engine.run(None) {
1266 Err(EngineError::Io(err)) => {
1267 assert_eq!(err.raw_os_error(), Some(errno));
1268 }
1269 other => panic!("expected EngineError::Io({}), got: {:?}", errno, other),
1270 }
1271 assert!(!engine.is_running());
1272 assert!(engine.exited());
1273 }
1274 }
1275
1276 #[test]
1277 fn test_engine_eintr_is_retried() {
1278 let backend = IntrThenFailBackend {
1281 eintr_count: 2,
1282 final_errno: libc::EBADF,
1283 wait_calls: 0,
1284 };
1285 let mut engine = Engine::with_backend(backend, 0);
1286
1287 match engine.run(None) {
1288 Err(EngineError::Io(err)) => {
1289 assert_eq!(err.raw_os_error(), Some(libc::EBADF));
1290 }
1291 other => panic!("expected EngineError::Io(EBADF), got: {:?}", other),
1292 }
1293 assert_eq!(engine.poll_backend.wait_calls, 3);
1295 assert!(!engine.is_running());
1296 assert!(engine.exited());
1297 }
1298
1299 #[test]
1300 fn test_engine_timeout_leaves_clean_state() {
1301 let mut engine = Engine::with_backend(NullBackend, 0);
1304 match engine.run(Some(0.0)) {
1305 Err(EngineError::Timeout) => {}
1306 other => panic!("expected EngineError::Timeout, got: {:?}", other),
1307 }
1308 assert!(!engine.is_running());
1309 assert!(engine.exited());
1310 }
1311
1312 #[test]
1315 fn test_engine_timer_creation() {
1316 let timer = EngineTimer::new(1.0, -1.0, false, || {});
1317 assert!(timer.base().is_valid());
1318 assert_eq!(timer.base().fire_delay(), 1.0);
1319 assert_eq!(timer.base().interval(), -1.0);
1320 assert!(!timer.base().autoclose());
1321 }
1322
1323 #[test]
1324 fn test_engine_timer_fire_calls_handler() {
1325 use std::sync::{
1326 atomic::{AtomicUsize, Ordering},
1327 Arc,
1328 };
1329 let counter = Arc::new(AtomicUsize::new(0));
1330 let counter_clone = counter.clone();
1331
1332 let mut timer = EngineTimer::new(0.5, -1.0, false, move || {
1333 counter_clone.fetch_add(1, Ordering::SeqCst);
1334 });
1335
1336 assert_eq!(counter.load(Ordering::SeqCst), 0);
1337 timer.fire();
1338 assert_eq!(counter.load(Ordering::SeqCst), 1);
1339 timer.fire();
1340 assert_eq!(counter.load(Ordering::SeqCst), 2);
1341 }
1342
1343 #[test]
1344 fn test_engine_timer_invalidate() {
1345 let mut timer = EngineTimer::new(1.0, -1.0, false, || {});
1346 assert!(timer.base().is_valid());
1347 timer.base_mut().invalidate();
1348 assert!(!timer.base().is_valid());
1349 }
1350
1351 #[test]
1352 fn test_engine_timer_debug() {
1353 let timer = EngineTimer::new(1.0, -1.0, false, || {});
1354 let debug_str = format!("{:?}", timer);
1355 assert!(debug_str.contains("EngineTimer"));
1356 assert!(debug_str.contains("<fn>"));
1357 }
1358
1359 #[test]
1360 fn test_engine_timer_with_autoclose() {
1361 let timer = EngineTimer::new(2.0, 0.5, true, || {});
1362 assert!(timer.base().autoclose());
1363 assert_eq!(timer.base().interval(), 0.5);
1364 }
1365}