1use std::io;
12use std::time::Duration;
13
14mod epoll;
15mod iocp;
16mod iouring;
17mod kqueue;
18
19pub use epoll::EpollReactor;
20pub use iocp::IocpReactor;
21pub use iouring::IoUringReactor;
22pub use kqueue::KqueueReactor;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub struct Token(pub usize);
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub struct Interest {
31 pub readable: bool,
33 pub writable: bool,
35}
36
37impl Interest {
38 pub const READABLE: Interest = Interest {
40 readable: true,
41 writable: false,
42 };
43
44 pub const WRITABLE: Interest = Interest {
46 readable: false,
47 writable: true,
48 };
49
50 pub const BOTH: Interest = Interest {
52 readable: true,
53 writable: true,
54 };
55}
56
57#[derive(Debug, Clone)]
59pub struct Event {
60 pub token: Token,
62 pub readable: bool,
64 pub writable: bool,
66 pub error: bool,
68 pub closed: bool,
70}
71
72impl Event {
73 pub fn new(token: Token) -> Self {
75 Self {
76 token,
77 readable: false,
78 writable: false,
79 error: false,
80 closed: false,
81 }
82 }
83
84 pub fn with_readable(mut self) -> Self {
86 self.readable = true;
87 self
88 }
89
90 pub fn with_writable(mut self) -> Self {
92 self.writable = true;
93 self
94 }
95
96 pub fn with_error(mut self) -> Self {
98 self.error = true;
99 self
100 }
101
102 pub fn with_closed(mut self) -> Self {
104 self.closed = true;
105 self
106 }
107}
108
109#[derive(Debug)]
111pub struct Completion {
112 pub token: Token,
114 pub result: io::Result<usize>,
116}
117
118pub trait Reactor: Send + Sync {
123 fn poll(&mut self, timeout: Option<Duration>) -> io::Result<Vec<Event>>;
128
129 fn register(&mut self, fd: RawFd, interest: Interest) -> io::Result<Token>;
133
134 fn modify(&mut self, token: Token, interest: Interest) -> io::Result<()>;
136
137 fn deregister(&mut self, token: Token) -> io::Result<()>;
139
140 fn submit_read(&mut self, _token: Token, _buf: &mut [u8]) -> io::Result<Option<Completion>> {
145 Ok(None)
146 }
147
148 fn submit_write(&mut self, _token: Token, _buf: &[u8]) -> io::Result<Option<Completion>> {
153 Ok(None)
154 }
155
156 fn supports_async_io(&self) -> bool {
161 false
162 }
163
164 fn name(&self) -> &'static str;
166}
167
168#[cfg(unix)]
170pub type RawFd = std::os::unix::io::RawFd;
171
172#[cfg(windows)]
173pub type RawFd = std::os::windows::io::RawSocket;
174
175#[derive(Debug, Clone)]
177pub struct ReactorConfig {
178 pub max_events: usize,
180 pub prefer_io_uring: bool,
182}
183
184impl Default for ReactorConfig {
185 fn default() -> Self {
186 Self {
187 max_events: 1024,
188 prefer_io_uring: true,
189 }
190 }
191}
192
193pub fn create_reactor(config: ReactorConfig) -> io::Result<Box<dyn Reactor>> {
199 #[cfg(target_os = "linux")]
200 {
201 if config.prefer_io_uring {
202 match IoUringReactor::new(config.max_events) {
203 Ok(reactor) => return Ok(Box::new(reactor)),
204 Err(_) => {
205 }
207 }
208 }
209 Ok(Box::new(EpollReactor::new(config.max_events)?))
210 }
211
212 #[cfg(target_os = "macos")]
213 {
214 Ok(Box::new(KqueueReactor::new(config.max_events)?))
215 }
216
217 #[cfg(target_os = "windows")]
218 {
219 Ok(Box::new(IocpReactor::new(config.max_events)?))
220 }
221
222 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
223 {
224 Err(io::Error::new(
225 io::ErrorKind::Unsupported,
226 "No reactor implementation for this platform",
227 ))
228 }
229}
230
231pub fn create_default_reactor() -> io::Result<Box<dyn Reactor>> {
233 create_reactor(ReactorConfig::default())
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 #[test]
241 fn test_interest_constants() {
242 assert!(Interest::READABLE.readable);
243 assert!(!Interest::READABLE.writable);
244
245 assert!(!Interest::WRITABLE.readable);
246 assert!(Interest::WRITABLE.writable);
247
248 assert!(Interest::BOTH.readable);
249 assert!(Interest::BOTH.writable);
250 }
251
252 #[test]
253 fn test_event_builder() {
254 let event = Event::new(Token(42)).with_readable().with_writable();
255
256 assert_eq!(event.token, Token(42));
257 assert!(event.readable);
258 assert!(event.writable);
259 assert!(!event.error);
260 assert!(!event.closed);
261 }
262
263 #[test]
264 fn test_token_equality() {
265 assert_eq!(Token(1), Token(1));
266 assert_ne!(Token(1), Token(2));
267 }
268
269 #[test]
270 fn test_reactor_config_default() {
271 let config = ReactorConfig::default();
272 assert_eq!(config.max_events, 1024);
273 assert!(config.prefer_io_uring);
274 }
275
276 #[test]
277 fn test_create_default_reactor() {
278 let result = create_default_reactor();
280 assert!(result.is_ok());
283
284 let reactor = result.unwrap();
285 let name = reactor.name();
287 assert!(!name.is_empty());
288 }
289
290 #[test]
291 fn test_create_reactor_with_config() {
292 let config = ReactorConfig {
293 max_events: 512,
294 prefer_io_uring: false, };
296
297 let result = create_reactor(config);
298 assert!(result.is_ok());
299 }
300}