mdrv 0.0.5

Modular driver based on Mio for managing multiple connections over different protocols
Documentation
use std::mem;
use std::thread::{self, JoinHandle};

use ::channel::{channel, Sender};
use ::proxy::{Proxy};

use ::event_loop::{EventLoop};


#[derive(Debug)]
pub enum Error {}

pub enum Tx {
    Attach(Box<dyn Proxy + Send>),
    Terminate,
}

pub struct Driver {
    thr: Option<JoinHandle<()>>,
    tx: Sender<Tx>,
}

impl Driver {
    pub fn new() -> Result<Self, ::Error> {
        let (tx, rx) = channel();
        let thr = thread::spawn(move || {
            EventLoop::new(rx).unwrap().run_forever(1024, None).unwrap();
        });

        Ok(Driver {
            thr: Some(thr),
            tx: tx,
        })
    }

    pub fn attach(&mut self, proxy: Box<dyn Proxy + Send>) -> ::Result<()> {
        match self.tx.send(Tx::Attach(proxy)) {
            Ok(_) => Ok(()),
            Err(err) => Err(::Error::Channel(err.into())),
        }
    }
}

impl Drop for Driver {
    fn drop(&mut self) {
        self.tx.send(Tx::Terminate).unwrap();
        let thr = mem::replace(&mut self.thr, None).unwrap();
        thr.join().unwrap();
    }
}


#[cfg(test)]
mod test {
    use super::*;

    use ::channel::{SinglePoll};
    use ::proxy_handle::{ProxyWrapper, Handle};
    use ::dummy::{self, wait_msgs, wait_close, DummyProxy, DummyHandle};

    fn create_dummy() -> (
        ProxyWrapper<DummyProxy, dummy::Tx, dummy::Rx>,
        Handle<DummyHandle, dummy::Tx, dummy::Rx>,
        SinglePoll,
    ) {
        let (p, h) = dummy::create().unwrap();
        let sp = SinglePoll::new(&h.rx).unwrap();
        (p, h, sp)
    }

    fn test_attach(
        h: &mut Handle<DummyHandle, dummy::Tx, dummy::Rx>,
        sp: &mut SinglePoll,
    ) {
        wait_msgs(h, sp, 1).unwrap();
        assert_matches!(h.user.msgs.pop_front(), Some(dummy::Rx::Attached));
        assert_matches!(h.user.msgs.pop_front(), None);
    }

    fn test_detach(
        h: &mut Handle<DummyHandle, dummy::Tx, dummy::Rx>,
        sp: &mut SinglePoll,
    ) {
        wait_close(h, sp).unwrap();
        assert_matches!(h.user.msgs.pop_front(), Some(dummy::Rx::Detached));
        assert_matches!(h.user.msgs.pop_front(), Some(dummy::Rx::Closed));
        assert_matches!(h.user.msgs.pop_front(), None);
    }

    #[test]
    fn add_remove() {
        let mut drv = Driver::new().unwrap();
        let (p, mut h, mut sp) = create_dummy();

        drv.attach(Box::new(p)).unwrap();
        test_attach(&mut h, &mut sp);

        h.close().unwrap();
        test_detach(&mut h, &mut sp);
    }

    #[test]
    fn add_remove_multiple() {
        let mut drv = Driver::new().unwrap();
        let phs = (0..16).map(|_| create_dummy());
        let mut hs = Vec::new();

        for (p, h, sp) in phs {
            drv.attach(Box::new(p)).unwrap();
            hs.push((h, sp));
        }

        for (h, sp) in hs.iter_mut() {
            test_attach(h, sp);
        }

        for (h, _) in hs.iter_mut() {
            h.close().unwrap();
        }

        for (h, sp) in hs.iter_mut() {
            test_detach(h, sp);
        }

        for (h, _) in hs.iter() {
            assert_eq!(h.is_closed(), true);
        }
    }
}