1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#![deny(missing_docs)]

//! Simple wrapper around mio's [Poll](https://docs.rs/mio/latest/mio/struct.Poll.html) method.
//!
//! ``` rust
//! extern crate mio;
//! extern crate mio_poll_wrapper;
//!
//! use mio_poll_wrapper::PollWrapper;
//! use mio::net::TcpListener;
//! use std::collections::HashMap;
//!
//! fn main() {
//!     let mut handle = PollWrapper::new().unwrap();
//!
//!     let listener = TcpListener::bind(&"0.0.0.0:8000".parse().unwrap()).unwrap();
//!
//!     let process_token = handle.register(&listener).unwrap();
//!     let mut clients = HashMap::new();
//!
//!     let result: ::std::io::Result<()> = handle.handle(|event, handle| {
//!         if event.token() == process_token {
//!             let (stream, addr) = listener.accept()?;
//!             println!("Accepted socket from {:?}", addr);
//!             let token = handle.register(&stream)?;
//!             clients.insert(token, stream);
//!         } else if let Some(client) = clients.get_mut(&event.token()) {
//!             println!("Received data from client {:?}", client.peer_addr());
//!         }
//!         Ok(())
//!     });
//!
//!     if let Err(e) = result {
//!         println!("Could not execute: {:?}", e);
//!     }
//! }
//! ```

extern crate mio;

use mio::{Event, Evented, Events, Poll, PollOpt, Ready, Token};

/// A wrapper around mio's Poll method
///
/// You can create this
pub struct PollWrapper {
    poll: Poll,
    tokens: Vec<Token>,
    next_token_id: usize,
}

impl PollWrapper {
    /// Create a new poll wrapper
    pub fn new() -> ::std::io::Result<PollWrapper> {
        Ok(PollWrapper {
            poll: Poll::new()?,
            tokens: Vec::new(),
            next_token_id: 0,
        })
    }

    /// Start the poll routine. Every time an event gets received, the callback handler gets called.
    ///
    /// The first argument of the handler is the event that is received.
    ///
    /// The second argument is a handle. See [Handle] for more information.
    pub fn handle<E>(
        mut self,
        mut handler: impl FnMut(Event, &mut Handle) -> Result<(), E>,
    ) -> Result<(), E> {
        let mut events = Events::with_capacity(10);
        loop {
            self.poll.poll(&mut events, None).unwrap();
            for event in &events {
                let mut handle = Handle {
                    poll: &self.poll,
                    tokens: Vec::new(),
                    next_token_id: &mut self.next_token_id,
                };
                handler(event, &mut handle)?;
                for token in handle.tokens {
                    self.tokens.push(token);
                }
            }
        }
    }

    /// Register an evented with the poll.
    /// This returns the token that was registered.
    pub fn register(&mut self, evented: &impl Evented) -> ::std::io::Result<Token> {
        let token = Token(self.next_token_id);
        self.next_token_id += 1;
        self.poll
            .register(evented, token, Ready::all(), PollOpt::edge())?;
        self.tokens.push(token);
        Ok(token)
    }
}

/// A handle that gets passed to the callback method of [PollWrapper].
///
/// This handle allows you to register evented methods to the poll while the wrapper is running.
pub struct Handle<'a> {
    poll: &'a Poll,
    tokens: Vec<Token>,
    next_token_id: &'a mut usize,
}

impl<'a> Handle<'a> {
    /// Register an evented with the poll.
    /// This returns the token that was registered.
    pub fn register(&mut self, evented: &impl Evented) -> ::std::io::Result<Token> {
        let token = Token(*self.next_token_id);
        *self.next_token_id += 1;
        self.poll
            .register(evented, token, Ready::all(), PollOpt::edge())?;
        self.tokens.push(token);
        Ok(token)
    }
}