split up crate using feature flags

Individual socket types are only implemented when they are requested via
the feature flag. Also, unless the `os-poll` feature is specified, the
crate is a shell.
diff --git a/Cargo.toml b/Cargo.toml
index 192fd2d..93afdd9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,6 +24,11 @@
 publish = false
 
 [features]
+os-poll = []
+os-ext = []
+tcp = []
+udp = []
+uds = []
 
 [dependencies]
 log = "0.4.8"
diff --git a/src/lib.rs b/src/lib.rs
index 4b82558..490c2c9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -126,6 +126,9 @@
 #[cfg(unix)]
 pub mod unix {
     //! Unix only extensions.
+    #[cfg(feature = "uds")]
     pub use crate::sys::SocketAddr;
+
+    #[cfg(feature = "os-ext")]
     pub use crate::sys::SourceFd;
 }
diff --git a/src/net/mod.rs b/src/net/mod.rs
index 4c718ce..adbb2a9 100644
--- a/src/net/mod.rs
+++ b/src/net/mod.rs
@@ -7,13 +7,17 @@
 //!
 //! [portability guidelines]: ../struct.Poll.html#portability
 
+#[cfg(feature = "tcp")]
 mod tcp;
+#[cfg(feature = "tcp")]
 pub use self::tcp::{TcpListener, TcpStream};
 
+#[cfg(feature = "udp")]
 mod udp;
+#[cfg(feature = "udp")]
 pub use self::udp::UdpSocket;
 
-#[cfg(unix)]
+#[cfg(all(unix, feature = "uds"))]
 mod uds;
-#[cfg(unix)]
+#[cfg(all(unix, feature = "uds"))]
 pub use self::uds::{UnixDatagram, UnixListener, UnixStream};
diff --git a/src/poll.rs b/src/poll.rs
index 9495c82..23523e6 100644
--- a/src/poll.rs
+++ b/src/poll.rs
@@ -1,7 +1,7 @@
 use crate::{event, sys, Events, Interests, Token};
 
 use log::trace;
-#[cfg(unix)]
+#[cfg(all(unix, feature = "os-ext"))]
 use std::os::unix::io::{AsRawFd, RawFd};
 #[cfg(debug_assertions)]
 use std::sync::atomic::{AtomicUsize, Ordering};
@@ -379,7 +379,7 @@
     }
 }
 
-#[cfg(unix)]
+#[cfg(all(unix, feature = "os-ext"))]
 impl AsRawFd for Poll {
     fn as_raw_fd(&self) -> RawFd {
         self.registry.selector.as_raw_fd()
@@ -637,12 +637,14 @@
 
 #[cfg(debug_assertions)]
 impl SelectorId {
+    #[cfg(any(feature = "tcp", feature = "udp", feature = "uds"))]
     pub fn new() -> SelectorId {
         SelectorId {
             id: AtomicUsize::new(0),
         }
     }
 
+    #[cfg(any(feature = "tcp", feature = "udp", feature = "uds"))]
     pub fn associate_selector(&self, registry: &Registry) -> io::Result<()> {
         let selector_id = self.id.load(Ordering::SeqCst);
 
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 0270a2c..fc8b88c 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -5,17 +5,19 @@
 //! `event`: a module with various helper functions for `Event`, see
 //!          `crate::event::Event` for the required functions.
 
-#[cfg(unix)]
-pub use self::unix::{
-    event, Event, Events, Selector, SocketAddr, SourceFd, TcpListener, TcpStream, UdpSocket,
-    UnixDatagram, UnixListener, UnixStream, Waker,
-};
+#[cfg(all(unix, feature = "os-poll"))]
+pub use self::unix::*;
 
-#[cfg(unix)]
+#[cfg(all(unix, feature = "os-poll"))]
 mod unix;
 
-#[cfg(windows)]
-pub use self::windows::{event, Event, Events, Selector, TcpListener, TcpStream, UdpSocket, Waker};
+#[cfg(all(windows, feature = "os-poll"))]
+pub use self::windows::*;
 
-#[cfg(windows)]
+#[cfg(all(windows, feature = "os-poll"))]
 mod windows;
+
+#[cfg(not(feature = "os-poll"))]
+mod shell;
+#[cfg(not(feature = "os-poll"))]
+pub(crate) use self::shell::*;
diff --git a/src/sys/shell/mod.rs b/src/sys/shell/mod.rs
new file mode 100644
index 0000000..8247535
--- /dev/null
+++ b/src/sys/shell/mod.rs
@@ -0,0 +1,16 @@
+#![allow(warnings)]
+
+macro_rules! os_required {
+    () => { panic!("mio must be compiled with `os-poll` to run.") };
+}
+
+mod selector;
+pub(crate) use self::selector::{event, Event, Events, Selector};
+
+#[cfg(feature = "tcp")]
+mod tcp;
+#[cfg(feature = "tcp")]
+pub(crate) use self::tcp::{TcpStream, TcpListener};
+
+mod waker;
+pub(crate) use self::waker::Waker;
diff --git a/src/sys/shell/selector.rs b/src/sys/shell/selector.rs
new file mode 100644
index 0000000..2424569
--- /dev/null
+++ b/src/sys/shell/selector.rs
@@ -0,0 +1,84 @@
+use std::io;
+use std::time::Duration;
+
+#[derive(Debug)]
+pub struct Selector {
+}
+
+pub type Event = usize;
+
+pub type Events = Vec<Event>;
+
+impl Selector {
+    pub fn new() -> io::Result<Selector> {
+        os_required!();
+    }
+
+    #[cfg(debug_assertions)]
+    pub fn id(&self) -> usize {
+        os_required!();
+    }
+
+    pub fn try_clone(&self) -> io::Result<Selector> {
+        os_required!();
+    }
+
+    pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
+        os_required!();
+    }
+
+    /*
+    pub fn register(&self, fd: RawFd, token: Token, interests: Interests) -> io::Result<()> {
+        os_required!();
+    }
+
+    pub fn reregister(&self, fd: RawFd, token: Token, interests: Interests) -> io::Result<()> {
+        os_required!();
+    }
+
+    pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
+        os_required!();
+    }
+    */
+}
+
+pub mod event {
+    use crate::sys::Event;
+    use crate::Token;
+
+    pub fn token(event: &Event) -> Token {
+        os_required!();
+    }
+
+    pub fn is_readable(event: &Event) -> bool {
+        os_required!();
+    }
+
+    pub fn is_writable(event: &Event) -> bool {
+        os_required!();
+    }
+
+    pub fn is_error(event: &Event) -> bool {
+        os_required!();
+    }
+
+    pub fn is_read_closed(event: &Event) -> bool {
+        os_required!();
+    }
+
+    pub fn is_write_closed(event: &Event) -> bool {
+        os_required!();
+    }
+
+    pub fn is_priority(event: &Event) -> bool {
+        os_required!();
+    }
+
+    pub fn is_aio(_: &Event) -> bool {
+        os_required!();
+    }
+
+    pub fn is_lio(_: &Event) -> bool {
+        os_required!();
+    }
+}
diff --git a/src/sys/shell/tcp.rs b/src/sys/shell/tcp.rs
new file mode 100644
index 0000000..a97c4d6
--- /dev/null
+++ b/src/sys/shell/tcp.rs
@@ -0,0 +1,199 @@
+#![allow(warnings)]
+
+use crate::{event, Interests, Registry, Token};
+
+use std::fmt;
+use std::io::{self, IoSlice, IoSliceMut, Read, Write};
+use std::net::{self, SocketAddr};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+
+#[derive(Debug)]
+pub struct TcpListener {
+}
+
+impl TcpListener {
+    pub fn bind(addr: SocketAddr) -> io::Result<TcpListener> {
+        os_required!();
+    }
+
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        os_required!();
+    }
+
+    pub fn try_clone(&self) -> io::Result<TcpListener> {
+        os_required!();
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        os_required!();
+    }
+
+    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+        os_required!();
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        os_required!();
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        os_required!();
+    }
+}
+
+impl event::Source for TcpListener {
+    fn register(&self, registry: &Registry, token: Token, interests: Interests) -> io::Result<()> {
+        os_required!();
+    }
+
+    fn reregister(
+        &self,
+        registry: &Registry,
+        token: Token,
+        interests: Interests,
+    ) -> io::Result<()> {
+        os_required!();
+    }
+
+    fn deregister(&self, registry: &Registry) -> io::Result<()> {
+        os_required!();
+    }
+}
+
+impl FromRawFd for TcpListener {
+    unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
+        os_required!();
+    }
+}
+
+impl IntoRawFd for TcpListener {
+    fn into_raw_fd(self) -> RawFd {
+        os_required!();
+    }
+}
+
+impl AsRawFd for TcpListener {
+    fn as_raw_fd(&self) -> RawFd {
+        os_required!();
+    }
+}
+
+pub struct TcpStream {
+}
+
+impl TcpStream {
+    pub(crate) fn new(inner: net::TcpStream) -> TcpStream {
+        os_required!();
+    }
+
+    pub fn connect(addr: SocketAddr) -> io::Result<TcpStream> {
+        os_required!();
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        os_required!();
+    }
+
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        os_required!();
+    }
+
+    pub fn try_clone(&self) -> io::Result<TcpStream> {
+        os_required!();
+    }
+
+    pub fn shutdown(&self, how: net::Shutdown) -> io::Result<()> {
+        os_required!();
+    }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        os_required!();
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        os_required!();
+    }
+
+    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+        os_required!();
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        os_required!();
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        os_required!();
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        os_required!();
+    }
+}
+
+impl<'a> Read for &'a TcpStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        os_required!();
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        os_required!();
+    }
+}
+
+impl<'a> Write for &'a TcpStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        os_required!();
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        os_required!();
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        os_required!();
+    }
+}
+
+impl event::Source for TcpStream {
+    fn register(&self, registry: &Registry, token: Token, interests: Interests) -> io::Result<()> {
+        os_required!();
+    }
+
+    fn reregister(
+        &self,
+        registry: &Registry,
+        token: Token,
+        interests: Interests,
+    ) -> io::Result<()> {
+        os_required!();
+    }
+
+    fn deregister(&self, registry: &Registry) -> io::Result<()> {
+        os_required!();
+    }
+}
+
+impl fmt::Debug for TcpStream {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        os_required!();
+    }
+}
+
+impl FromRawFd for TcpStream {
+    unsafe fn from_raw_fd(fd: RawFd) -> TcpStream {
+        os_required!();
+    }
+}
+
+impl IntoRawFd for TcpStream {
+    fn into_raw_fd(self) -> RawFd {
+        os_required!();
+    }
+}
+
+impl AsRawFd for TcpStream {
+    fn as_raw_fd(&self) -> RawFd {
+        os_required!();
+    }
+}
diff --git a/src/sys/shell/waker.rs b/src/sys/shell/waker.rs
new file mode 100644
index 0000000..d294d75
--- /dev/null
+++ b/src/sys/shell/waker.rs
@@ -0,0 +1,23 @@
+use crate::sys::Selector;
+use crate::Token;
+
+use std::io;
+
+#[derive(Debug)]
+pub struct Waker {
+}
+
+impl Waker {
+    pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
+        os_required!();
+    }
+
+    pub fn wake(&self) -> io::Result<()> {
+        os_required!();
+    }
+
+    /// Reset the eventfd object, only need to call this if `wake` fails.
+    fn reset(&self) -> io::Result<()> {
+        os_required!();
+    }
+}
diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs
index 7ba8202..a1d35d5 100644
--- a/src/sys/unix/mod.rs
+++ b/src/sys/unix/mod.rs
@@ -5,7 +5,7 @@
     ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
         let res = unsafe { libc::$fn($($arg, )*) };
         if res == -1 {
-            Err(io::Error::last_os_error())
+            Err(std::io::Error::last_os_error())
         } else {
             Ok(res)
         }
@@ -20,13 +20,19 @@
 mod sourcefd;
 pub use self::sourcefd::SourceFd;
 
+#[cfg(feature = "tcp")]
 mod tcp;
+#[cfg(feature = "tcp")]
 pub use self::tcp::{TcpListener, TcpStream};
 
+#[cfg(feature = "udp")]
 mod udp;
+#[cfg(feature = "udp")]
 pub use self::udp::UdpSocket;
 
+#[cfg(feature = "uds")]
 mod uds;
+#[cfg(feature = "uds")]
 pub use self::uds::{SocketAddr, UnixDatagram, UnixListener, UnixStream};
 
 mod waker;
diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs
index bc6fe40..167c4a0 100644
--- a/src/sys/unix/net.rs
+++ b/src/sys/unix/net.rs
@@ -1,8 +1,8 @@
-use std::io;
-use std::mem::size_of_val;
+#[cfg(any(feature = "tcp", feature = "udp"))]
 use std::net::SocketAddr;
 
-pub fn new_ip_socket(addr: SocketAddr, socket_type: libc::c_int) -> io::Result<libc::c_int> {
+#[cfg(any(feature = "tcp", feature = "udp"))]
+pub fn new_ip_socket(addr: SocketAddr, socket_type: libc::c_int) -> std::io::Result<libc::c_int> {
     let domain = match addr {
         SocketAddr::V4(..) => libc::AF_INET,
         SocketAddr::V6(..) => libc::AF_INET6,
@@ -12,7 +12,8 @@
 }
 
 /// Create a new non-blocking socket.
-pub fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> io::Result<libc::c_int> {
+#[cfg(any(feature = "tcp", feature = "udp", feature = "uds"))]
+pub fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> std::io::Result<libc::c_int> {
     #[cfg(any(
         target_os = "android",
         target_os = "dragonfly",
@@ -46,7 +47,10 @@
     socket
 }
 
+#[cfg(any(feature = "tcp", feature = "udp"))]
 pub fn socket_addr(addr: &SocketAddr) -> (*const libc::sockaddr, libc::socklen_t) {
+    use std::mem::size_of_val;
+
     match addr {
         SocketAddr::V4(ref addr) => (
             addr as *const _ as *const libc::sockaddr,
diff --git a/src/sys/unix/selector/kqueue.rs b/src/sys/unix/selector/kqueue.rs
index 0675d55..9071833 100644
--- a/src/sys/unix/selector/kqueue.rs
+++ b/src/sys/unix/selector/kqueue.rs
@@ -75,6 +75,7 @@
     }
 
     #[cfg(debug_assertions)]
+    #[cfg(any(feature = "tcp", feature = "udp", feature = "uds"))]
     pub fn id(&self) -> usize {
         self.id
     }