mill_io/
lib.rs

1//! # Mill-IO
2//!
3//! A lightweight, production-ready event loop library for Rust that provides efficient non-blocking I/O management
4//! without relying on heavyweight async runtimes like Tokio.
5//!
6//! Mill-IO is a modular, reactor-based event loop built on top of [`mio`], offering cross-platform polling,
7//! configurable thread pool integration, and object pooling for high-performance applications that need
8//! fine-grained control over their I/O operations.
9//!
10//! ## Core Philosophy
11//!
12//! Mill-IO was designed for applications that require:
13//! - **Predictable performance** with minimal runtime overhead
14//! - **Runtime-agnostic architecture** that doesn't force async/await patterns
15//! - **Direct control** over concurrency and resource management
16//! - **Minimal dependencies** for reduced attack surface and faster builds
17//!
18//! ## Features
19//!
20//! - **Runtime-agnostic**: No dependency on Tokio or other async runtimes
21//! - **Cross-platform**: Leverages mio's polling abstraction (epoll, kqueue, IOCP)
22//! - **Thread pool integration**: Configurable worker threads for handling I/O events
23//! - **Object pooling**: Reduces allocation overhead for frequent operations
24//! - **Clean API**: Simple registration and handler interface
25//! - **Thread-safe**: Lock-free operations in hot paths
26//!
27//! ## Architecture Overview
28//!
29//! ```text
30//! ┌─────────────┐    ┌──────────────┐    ┌─────────────┐
31//! │ EventLoop   │───▶│   Reactor    │───▶│ PollHandle  │
32//! └─────────────┘    └──────────────┘    └─────────────┘
33//!                             │
34//!                             ▼
35//!                    ┌──────────────┐    ┌─────────────┐
36//!                    │ ThreadPool   │───▶│   Workers   │
37//!                    └──────────────┘    └─────────────┘
38//! ```
39//!
40//! ## Quick Start
41//!
42//! ```rust
43//! use mill_io::{EventLoop, EventHandler};
44//! use mio::{net::TcpListener, Interest, Token};
45//!
46//! struct EchoHandler;
47//!
48//! impl EventHandler for EchoHandler {
49//!     fn handle_event(&self, event: &mio::event::Event) {
50//!         println!("Received event: {:?}", event);
51//!         // Handle incoming connections and data
52//!     }
53//! }
54//!
55//! fn main() -> Result<(), Box<dyn std::error::Error>> {
56//!     // Create event loop with default configuration
57//!     let event_loop = EventLoop::default();
58//!     
59//!     // Bind to localhost
60//!     let mut listener = TcpListener::bind("127.0.0.1:8080")?;
61//!
62//!     // Register the listener with a handler
63//!     event_loop.register(
64//!         &mut listener,
65//!         Token(1),
66//!         Interest::READABLE,
67//!         EchoHandler
68//!     )?;
69//!
70//!     println!("Server listening on 127.0.0.1:8080");
71//!     
72//!     // Start the event loop (blocks until stopped)
73//!     event_loop.run()?;
74//!
75//!     Ok(())
76//! }
77//! ```
78//!
79//! ## Advanced Configuration
80//!
81//! ```rust
82//! use mill_io::EventLoop;
83//!
84//! // Create event loop with custom configuration
85//! let event_loop = EventLoop::new(
86//!     8,      // 8 worker threads
87//!     1024,   // Handle up to 1024 events per poll
88//!     100     // 100ms poll timeout
89//! )?;
90//! ```
91//!
92//! ## Module Overview
93//!
94//! - [`EventLoop`]: Main entry point for registering I/O sources and running the event loop
95//! - [`EventHandler`]: Trait for implementing custom event handling logic
96//! - [`reactor`]: Core reactor implementation managing the event loop lifecycle
97//! - [`thread_pool`]: Configurable thread pool for distributing work
98//! - [`object_pool`]: Memory-efficient object pooling for buffers and resources
99//! - [`poll`]: Cross-platform polling abstraction and handler registry
100//! - [`error`]: Error types and result handling
101//!
102//! For comprehensive examples and architectural details, see the [README](../README.md) 
103//! and [Architecture Guide](../docs/Arch.md).
104
105#![cfg_attr(feature = "unstable-mpmc", feature(mpmc_channel))]
106
107use mio::{Interest, Token};
108pub mod error;
109pub mod handler;
110pub mod object_pool;
111pub mod poll;
112pub mod reactor;
113pub mod thread_pool;
114
115pub use handler::EventHandler;
116pub use object_pool::{ObjectPool, PooledObject};
117
118use crate::{
119    error::Result,
120    reactor::{DEFAULT_EVENTS_CAPACITY, DEFAULT_POLL_TIMEOUT_MS},
121    thread_pool::DEFAULT_POOL_CAPACITY,
122};
123
124/// A convenient prelude module that re-exports commonly used types and traits.
125///
126/// This module provides a convenient way to import the most commonly used items from mill-io:
127///
128/// ```rust
129/// use mill_io::prelude::*;
130/// ```
131///
132/// This brings into scope:
133/// - [`EventHandler`] - Trait for implementing event handling logic
134/// - [`ObjectPool`] and [`PooledObject`] - Object pooling utilities
135/// - [`Reactor`] - Core reactor implementation (advanced usage)
136/// - [`ThreadPool`] - Thread pool implementation (advanced usage)
137pub mod prelude {
138    pub use crate::handler::EventHandler;
139    pub use crate::object_pool::{ObjectPool, PooledObject};
140    pub use crate::reactor::{self, Reactor};
141    pub use crate::thread_pool::{self, ThreadPool};
142}
143
144/// The main event loop structure for registering I/O sources and handling events.
145///
146/// `EventLoop` is the primary interface for Mill-IO, providing a simple API for:
147/// - Registering I/O sources (sockets, files, etc.) with event handlers
148/// - Starting and stopping the event loop
149/// - Managing the underlying reactor and thread pool
150///
151/// The event loop uses a reactor pattern internally, where I/O events are detected
152/// by the polling mechanism and dispatched to registered handlers via a thread pool.
153///
154/// # Examples
155///
156/// Basic usage with default configuration:
157///
158/// ```rust,no_run
159/// use mill_io::{EventLoop, EventHandler};
160/// use mio::{net::TcpListener, Interest, Token};
161///
162/// struct MyHandler;
163/// impl EventHandler for MyHandler {
164///     fn handle_event(&self, event: &mio::event::Event) {
165///         println!("Event received: {:?}", event);
166///     }
167/// }
168///
169/// let event_loop = EventLoop::default();
170/// let mut listener = TcpListener::bind("127.0.0.1:0")?;
171/// 
172/// event_loop.register(&mut listener, Token(0), Interest::READABLE, MyHandler)?;
173/// event_loop.run()?; // Blocks until stopped
174/// # Ok::<(), Box<dyn std::error::Error>>(())
175/// ```
176///
177/// Custom configuration:
178///
179/// ```rust,no_run
180/// use mill_io::EventLoop;
181///
182/// let event_loop = EventLoop::new(
183///     4,      // 4 worker threads
184///     512,    // Buffer for 512 events per poll
185///     50      // 50ms poll timeout
186/// )?;
187/// # Ok::<(), Box<dyn std::error::Error>>(())
188/// ```
189pub struct EventLoop {
190    reactor: reactor::Reactor,
191}
192
193impl Default for EventLoop {
194    /// Creates a new `EventLoop` with default configuration.
195    ///
196    /// The default configuration uses:
197    /// - 4 worker threads ([`DEFAULT_POOL_CAPACITY`])
198    /// - 1024 events capacity ([`DEFAULT_EVENTS_CAPACITY`])
199    /// - 100ms poll timeout ([`DEFAULT_POLL_TIMEOUT_MS`])
200    ///
201    /// # Panics
202    /// 
203    /// Panics if the reactor cannot be initialized with default settings.
204    fn default() -> Self {
205        let reactor = reactor::Reactor::new(
206            DEFAULT_POOL_CAPACITY,
207            DEFAULT_EVENTS_CAPACITY,
208            DEFAULT_POLL_TIMEOUT_MS,
209        )
210        .unwrap();
211        Self { reactor }
212    }
213}
214
215impl EventLoop {
216    /// Creates a new `EventLoop` with custom configuration.
217    ///
218    /// # Arguments
219    /// * `workers` - Number of worker threads in the thread pool (recommended: num_cpus)
220    /// * `events_capacity` - Maximum number of events to poll per iteration (typical: 512-4096)
221    /// * `poll_timeout_ms` - Poll timeout in milliseconds (balance between latency and CPU usage)
222    ///
223    /// # Errors
224    /// 
225    /// Returns an error if:
226    /// - The reactor cannot be initialized
227    /// - The thread pool cannot be created
228    /// - The polling mechanism fails to initialize
229    ///
230    /// # Examples
231    ///
232    /// ```rust,no_run
233    /// use mill_io::EventLoop;
234    ///
235    /// // High-throughput configuration
236    /// let event_loop = EventLoop::new(8, 2048, 50)?;
237    ///
238    /// // Low-latency configuration
239    /// let event_loop = EventLoop::new(2, 256, 10)?;
240    /// # Ok::<(), Box<dyn std::error::Error>>(())
241    /// ```
242    pub fn new(workers: usize, events_capacity: usize, poll_timeout_ms: u64) -> Result<Self> {
243        let reactor = reactor::Reactor::new(workers, events_capacity, poll_timeout_ms)?;
244        Ok(Self { reactor })
245    }
246
247    /// Registers an I/O source with the event loop and associates it with a handler.
248    ///
249    /// This method registers an I/O source (such as a TCP listener or socket) with the event loop.
250    /// When events occur on the source, the provided handler will be invoked on a worker thread.
251    ///
252    ///
253    /// # Arguments
254    /// * `source` - The I/O source to register (e.g., [`mio::net::TcpListener`])
255    /// * `token` - Unique token for identifying events from this source
256    /// * `interests` - I/O events to listen for ([`mio::Interest::READABLE`], [`mio::Interest::WRITABLE`])
257    /// * `handler` - Event handler that will process events from this source
258    ///
259    /// # Errors
260    /// 
261    /// Returns an error if:
262    /// - The token is already in use
263    /// - The source cannot be registered with the underlying poll mechanism
264    /// - The handler registry is full
265    ///
266    /// # Examples
267    ///
268    /// ```rust,no_run
269    /// use mill_io::{EventLoop, EventHandler};
270    /// use mio::{net::TcpListener, Interest, Token};
271    ///
272    /// struct ConnectionHandler;
273    /// impl EventHandler for ConnectionHandler {
274    ///     fn handle_event(&self, event: &mio::event::Event) {
275    ///         // Handle new connections
276    ///     }
277    /// }
278    ///
279    /// let event_loop = EventLoop::default();
280    /// let mut listener = TcpListener::bind("0.0.0.0:8080")?;
281    ///
282    /// event_loop.register(
283    ///     &mut listener,
284    ///     Token(0),
285    ///     Interest::READABLE,
286    ///     ConnectionHandler
287    /// )?;
288    /// # Ok::<(), Box<dyn std::error::Error>>(())
289    /// ```
290    pub fn register<H, S>(
291        &self,
292        source: &mut S,
293        token: Token,
294        interests: Interest,
295        handler: H,
296    ) -> Result<()>
297    where
298        H: EventHandler + Send + Sync + 'static,
299        S: mio::event::Source + ?Sized,
300    {
301        self.reactor
302            .poll_handle
303            .register(source, token, interests, handler)
304    }
305
306    /// Deregisters an I/O source from the event loop.
307    ///
308    /// Removes the source from the polling mechanism and clears its associated handler.
309    /// After deregistration, no more events will be delivered for this source.
310    ///
311    /// # Arguments
312    /// * `source` - The I/O source to deregister
313    /// * `token` - Token associated with the source during registration
314    ///
315    /// # Errors
316    /// 
317    /// Returns an error if:
318    /// - The source is not currently registered
319    /// - The deregistration fails at the OS level
320    /// - The token is invalid
321    ///
322    /// # Examples
323    ///
324    /// ```rust,no_run
325    /// use mill_io::{EventLoop, EventHandler};
326    /// use mio::{net::TcpListener, Interest, Token};
327    ///
328    /// struct Handler;
329    /// impl EventHandler for Handler {
330    ///     fn handle_event(&self, _: &mio::event::Event) {}
331    /// }
332    ///
333    /// let event_loop = EventLoop::default();
334    /// let mut listener = TcpListener::bind("127.0.0.1:0")?;
335    /// let token = Token(0);
336    ///
337    /// // Register
338    /// event_loop.register(&mut listener, token, Interest::READABLE, Handler)?;
339    ///
340    /// // Later, deregister
341    /// event_loop.deregister(&mut listener, token)?;
342    /// # Ok::<(), Box<dyn std::error::Error>>(())
343    /// ```
344    pub fn deregister<S>(&self, source: &mut S, token: Token) -> Result<()>
345    where
346        S: mio::event::Source + ?Sized,
347    {
348        self.reactor.poll_handle.deregister(source, token)
349    }
350
351    /// Runs the event loop, blocking the current thread and dispatching events.
352    ///
353    /// This method starts the reactor's main loop, which will:
354    /// 1. Poll for I/O events using the configured timeout
355    /// 2. Dispatch events to registered handlers via the thread pool
356    /// 3. Continue until [`stop()`](Self::stop) is called or an error occurs
357    ///
358    /// The method blocks the calling thread and will only return when the event loop
359    /// is stopped or encounters a fatal error.
360    ///
361    /// # Errors
362    /// 
363    /// Returns an error if:
364    /// - The polling mechanism fails
365    /// - The thread pool encounters a fatal error
366    /// - System resources are exhausted
367    ///
368    /// # Examples
369    ///
370    /// ```rust,no_run
371    /// use mill_io::EventLoop;
372    /// use std::thread;
373    /// use std::time::Duration;
374    ///
375    /// let event_loop = EventLoop::default();
376    ///
377    /// // Stop the loop after 5 seconds (in another thread)
378    /// let event_loop_clone = event_loop.clone(); // Note: EventLoop would need to implement Clone
379    /// thread::spawn(move || {
380    ///     thread::sleep(Duration::from_secs(5));
381    ///     // event_loop_clone.stop(); // Would stop the loop
382    /// });
383    ///
384    /// // This blocks until stopped
385    /// // event_loop.run()?;
386    /// # Ok::<(), Box<dyn std::error::Error>>(())
387    /// ```
388    pub fn run(&self) -> Result<()> {
389        self.reactor.run()
390    }
391
392    /// Signals the event loop to stop gracefully.
393    ///
394    /// This method initiates a graceful shutdown of the event loop. It sends a shutdown
395    /// signal to the reactor, which will cause the main loop to exit after finishing
396    /// the current polling cycle.
397    ///
398    /// This method is non-blocking and returns immediately. The actual shutdown happens
399    /// asynchronously, and [`run()`](Self::run) will return once the shutdown is complete.
400    ///
401    /// # Thread Safety
402    ///
403    /// This method is thread-safe and can be called from any thread, making it suitable
404    /// for use in signal handlers or from other threads.
405    ///
406    /// # Examples
407    ///
408    /// ```rust,no_run
409    /// use mill_io::EventLoop;
410    /// use std::thread;
411    /// use std::sync::Arc;
412    ///
413    /// let event_loop = Arc::new(EventLoop::default());
414    /// let event_loop_clone = Arc::clone(&event_loop);
415    ///
416    /// // Start event loop in background thread
417    /// let handle = thread::spawn(move || {
418    ///     event_loop_clone.run()
419    /// });
420    ///
421    /// // Stop after some time
422    /// thread::sleep(std::time::Duration::from_secs(1));
423    /// event_loop.stop();
424    ///
425    /// // Wait for shutdown
426    /// handle.join().unwrap();
427    /// # Ok::<(), Box<dyn std::error::Error>>(())
428    /// ```
429    pub fn stop(&self) {
430        let shutdown_handler = self.reactor.get_shutdown_handle();
431        shutdown_handler.shutdown();
432    }
433}