<commit_before>//! Async WebSocket usage.
//!
//! This library is an implementation of WebSocket handshakes and streams. It
//! is based on the crate which implements all required WebSocket protocol
//! logic. So this crate basically just brings tokio support / tokio integration
//! to it.
//!
//! Each WebSocket stream implements the required `Stream` and `Sink` traits,
//! so the socket is just a stream of messages coming in and going out.

#![deny(
    missing_docs,
    unused_must_use,
    unused_mut,
    unused_imports,
    unused_import_braces
)]

pub use tungstenite;

mod compat;
#[cfg(feature = "connect")]
mod connect;
mod handshake;
#[cfg(feature = "stream")]
pub mod stream;

use std::io::{Read, Write};

use compat::{cvt, AllowStd, ContextWaker};
use futures_util::{sink::{Sink, SinkExt}, stream::Stream};
use log::*;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncWrite};

use tungstenite::{
    client::IntoClientRequest,
    error::Error as WsError,
    handshake::{
        client::{ClientHandshake, Request, Response},
        server::{Callback, NoCallback},
    },
    protocol::{Message, Role, WebSocket, WebSocketConfig},
    server,
};

#[cfg(feature = "connect")]
pub use connect::{client_async_tls, connect_async};

#[cfg(all(feature = "connect", feature = "tls"))]
pub use connect::MaybeTlsStream;
use std::error::Error;
use tungstenite::protocol::CloseFrame;

/// Creates a WebSocket handshake from a request and a stream.
/// For convenience, the user may call this with a url string, a URL,
/// or a `Request`. Calling with `Request` allows the user to add
/// a WebSocket protocol or other custom headers.
///
/// Internally, this custom creates a handshake representation and returns
/// a future representing the resolution of the WebSocket handshake. The
/// returned future will resolve to either `WebSocketStream<S>` or `Error`
/// depending on whether the handshake is successful.
///
/// This is typically used for clients who have already established, for
/// example, a TCP connection to the remote server.
pub async fn client_async<'a, R, S>(
    request: R,
    stream: S,
) -> Result<(WebSocketStream<S>, Response), WsError>
where
    R: IntoClientRequest + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    client_async_with_config(request, stream, None).await
}

/// The same as `client_async()` but the one can specify a websocket configuration.
/// Please refer to `client_async()` for more details.
pub async fn client_async_with_config<'a, R, S>(
    request: R,
    stream: S,
    config: Option<WebSocketConfig>,
) -> Result<(WebSocketStream<S>, Response), WsError>
where
    R: IntoClientRequest + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    let f = handshake::client_handshake(stream, move |allow_std| {
        let request = request.into_client_request()?;
        let cli_handshake = ClientHandshake::start(allow_std, request, config)?;
        cli_handshake.handshake()
    });
    f.await.map_err(|e| {
        WsError::Io(std::io::Error::new(
            std::io::ErrorKind::Other,
            e.description(),
        ))
    })
}

/// Accepts a new WebSocket connection with the provided stream.
///
/// This function will internally call `server::accept` to create a
/// handshake representation and returns a future representing the
/// resolution of the WebSocket handshake. The returned future will resolve
/// to either `WebSocketStream<S>` or `Error` depending if it's successful
/// or not.
///
/// This is typically used after a socket has been accepted from a
/// `TcpListener`. That socket is then passed to this function to perform
/// the server half of the accepting a client's websocket connection.
pub async fn accept_async<S>(stream: S) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    accept_hdr_async(stream, NoCallback).await
}

/// The same as `accept_async()` but the one can specify a websocket configuration.
/// Please refer to `accept_async()` for more details.
pub async fn accept_async_with_config<S>(
    stream: S,
    config: Option<WebSocketConfig>,
) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    accept_hdr_async_with_config(stream, NoCallback, config).await
}

/// Accepts a new WebSocket connection with the provided stream.
///
/// This function does the same as `accept_async()` but accepts an extra callback
/// for header processing. The callback receives headers of the incoming
/// requests and is able to add extra headers to the reply.
pub async fn accept_hdr_async<S, C>(stream: S, callback: C) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
    C: Callback + Unpin,
{
    accept_hdr_async_with_config(stream, callback, None).await
}

/// The same as `accept_hdr_async()` but the one can specify a websocket configuration.
/// Please refer to `accept_hdr_async()` for more details.
pub async fn accept_hdr_async_with_config<S, C>(
    stream: S,
    callback: C,
    config: Option<WebSocketConfig>,
) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
    C: Callback + Unpin,
{
    let f = handshake::server_handshake(stream, move |allow_std| {
        server::accept_hdr_with_config(allow_std, callback, config)
    });
    f.await.map_err(|e| {
        WsError::Io(std::io::Error::new(
            std::io::ErrorKind::Other,
            e.description(),
        ))
    })
}

/// A wrapper around an underlying raw stream which implements the WebSocket
/// protocol.
///
/// A `WebSocketStream<S>` represents a handshake that has been completed
/// successfully and both the server and the client are ready for receiving
/// and sending data. Message from a `WebSocketStream<S>` are accessible
/// through the respective `Stream` and `Sink`. Check more information about
/// them in `futures-rs` crate documentation or have a look on the examples
/// and unit tests for this crate.
#[derive(Debug)]
pub struct WebSocketStream<S> {
    inner: WebSocket<AllowStd<S>>,
}

impl<S> WebSocketStream<S> {
    /// Convert a raw socket into a WebSocketStream without performing a
    /// handshake.
    pub async fn from_raw_socket(stream: S, role: Role, config: Option<WebSocketConfig>) -> Self
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake::without_handshake(stream, move |allow_std| {
            WebSocket::from_raw_socket(allow_std, role, config)
        })
        .await
    }

    /// Convert a raw socket into a WebSocketStream without performing a
    /// handshake.
    pub async fn from_partially_read(
        stream: S,
        part: Vec<u8>,
        role: Role,
        config: Option<WebSocketConfig>,
    ) -> Self
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake::without_handshake(stream, move |allow_std| {
            WebSocket::from_partially_read(allow_std, part, role, config)
        })
        .await
    }

    pub(crate) fn new(ws: WebSocket<AllowStd<S>>) -> Self {
        WebSocketStream { inner: ws }
    }

    fn with_context<F, R>(&mut self, ctx: Option<(ContextWaker, &mut Context<'_>)>, f: F) -> R
    where
        S: Unpin,
        F: FnOnce(&mut WebSocket<AllowStd<S>>) -> R,
        AllowStd<S>: Read + Write,
    {
        trace!("{}:{} WebSocketStream.with_context", file!(), line!());
        if let Some((kind, ctx)) = ctx {
            self.inner.get_mut().set_waker(kind, &ctx.waker());
        }
        f(&mut self.inner)
    }

    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        &self.inner.get_ref().get_ref()
    }

    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        self.inner.get_mut().get_mut()
    }

    /// Close the underlying web socket
    pub async fn close(&mut self, msg: Option<CloseFrame<'_>>) -> Result<(), WsError>
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        let msg = msg.map(|msg| msg.into_owned());
        self.send(Message::Close(msg)).await
    }
}

impl<T> Stream for WebSocketStream<T>
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Item = Result<Message, WsError>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        trace!("{}:{} Stream.poll_next", file!(), line!());
        match futures_util::ready!(self.with_context(Some((ContextWaker::Read, cx)), |s| {
            trace!(
                "{}:{} Stream.with_context poll_next -> read_message()",
                file!(),
                line!()
            );
            cvt(s.read_message())
        })) {
            Ok(v) => Poll::Ready(Some(Ok(v))),
            Err(WsError::AlreadyClosed) | Err(WsError::ConnectionClosed) => Poll::Ready(None),
            Err(e) => Poll::Ready(Some(Err(e))),
        }
    }
}

impl<T> Sink<Message> for WebSocketStream<T>
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Error = WsError;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        (*self).with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.write_pending()))
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        match (*self).with_context(None, |s| s.write_message(item)) {
            Ok(()) => Ok(()),
            Err(::tungstenite::Error::Io(ref err))
                if err.kind() == std::io::ErrorKind::WouldBlock =>
            {
                // the message was accepted and queued
                // isn't an error.
                Ok(())
            }
            Err(e) => {
                debug!("websocket start_send error: {}", e);
                Err(e)
            }
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        (*self).with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.write_pending()))
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        match (*self).with_context(Some((ContextWaker::Write, cx)), |s| s.close(None)) {
            Ok(()) => Poll::Ready(Ok(())),
            Err(::tungstenite::Error::ConnectionClosed) => Poll::Ready(Ok(())),
            Err(err) => {
                debug!("websocket close error: {}", err);
                Poll::Ready(Err(err))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::compat::AllowStd;
    #[cfg(feature = "connect")]
    use crate::connect::encryption::AutoStream;
    use crate::WebSocketStream;
    use std::io::{Read, Write};
    use tokio::io::{AsyncReadExt, AsyncWriteExt};

    fn is_read<T: Read>() {}
    fn is_write<T: Write>() {}
    fn is_async_read<T: AsyncReadExt>() {}
    fn is_async_write<T: AsyncWriteExt>() {}
    fn is_unpin<T: Unpin>() {}

    #[test]
    fn web_socket_stream_has_traits() {
        is_read::<AllowStd<tokio::net::TcpStream>>();
        is_write::<AllowStd<tokio::net::TcpStream>>();

        #[cfg(feature = "connect")]
        is_async_read::<AutoStream<tokio::net::TcpStream>>();
        #[cfg(feature = "connect")]
        is_async_write::<AutoStream<tokio::net::TcpStream>>();

        is_unpin::<WebSocketStream<tokio::net::TcpStream>>();
        #[cfg(feature = "connect")]
        is_unpin::<WebSocketStream<AutoStream<tokio::net::TcpStream>>>();
    }
}
<commit_msg>Replace `Error::description` with `to_string`<commit_after>//! Async WebSocket usage.
//!
//! This library is an implementation of WebSocket handshakes and streams. It
//! is based on the crate which implements all required WebSocket protocol
//! logic. So this crate basically just brings tokio support / tokio integration
//! to it.
//!
//! Each WebSocket stream implements the required `Stream` and `Sink` traits,
//! so the socket is just a stream of messages coming in and going out.

#![deny(
    missing_docs,
    unused_must_use,
    unused_mut,
    unused_imports,
    unused_import_braces
)]

pub use tungstenite;

mod compat;
#[cfg(feature = "connect")]
mod connect;
mod handshake;
#[cfg(feature = "stream")]
pub mod stream;

use std::io::{Read, Write};

use compat::{cvt, AllowStd, ContextWaker};
use futures_util::{
    sink::{Sink, SinkExt},
    stream::Stream,
};
use log::*;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncWrite};

use tungstenite::{
    client::IntoClientRequest,
    error::Error as WsError,
    handshake::{
        client::{ClientHandshake, Request, Response},
        server::{Callback, NoCallback},
    },
    protocol::{Message, Role, WebSocket, WebSocketConfig},
    server,
};

#[cfg(feature = "connect")]
pub use connect::{client_async_tls, connect_async};

#[cfg(all(feature = "connect", feature = "tls"))]
pub use connect::MaybeTlsStream;
use tungstenite::protocol::CloseFrame;

/// Creates a WebSocket handshake from a request and a stream.
/// For convenience, the user may call this with a url string, a URL,
/// or a `Request`. Calling with `Request` allows the user to add
/// a WebSocket protocol or other custom headers.
///
/// Internally, this custom creates a handshake representation and returns
/// a future representing the resolution of the WebSocket handshake. The
/// returned future will resolve to either `WebSocketStream<S>` or `Error`
/// depending on whether the handshake is successful.
///
/// This is typically used for clients who have already established, for
/// example, a TCP connection to the remote server.
pub async fn client_async<'a, R, S>(
    request: R,
    stream: S,
) -> Result<(WebSocketStream<S>, Response), WsError>
where
    R: IntoClientRequest + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    client_async_with_config(request, stream, None).await
}

/// The same as `client_async()` but the one can specify a websocket configuration.
/// Please refer to `client_async()` for more details.
pub async fn client_async_with_config<'a, R, S>(
    request: R,
    stream: S,
    config: Option<WebSocketConfig>,
) -> Result<(WebSocketStream<S>, Response), WsError>
where
    R: IntoClientRequest + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    let f = handshake::client_handshake(stream, move |allow_std| {
        let request = request.into_client_request()?;
        let cli_handshake = ClientHandshake::start(allow_std, request, config)?;
        cli_handshake.handshake()
    });
    f.await.map_err(|e| {
        WsError::Io(std::io::Error::new(
            std::io::ErrorKind::Other,
            e.to_string(),
        ))
    })
}

/// Accepts a new WebSocket connection with the provided stream.
///
/// This function will internally call `server::accept` to create a
/// handshake representation and returns a future representing the
/// resolution of the WebSocket handshake. The returned future will resolve
/// to either `WebSocketStream<S>` or `Error` depending if it's successful
/// or not.
///
/// This is typically used after a socket has been accepted from a
/// `TcpListener`. That socket is then passed to this function to perform
/// the server half of the accepting a client's websocket connection.
pub async fn accept_async<S>(stream: S) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    accept_hdr_async(stream, NoCallback).await
}

/// The same as `accept_async()` but the one can specify a websocket configuration.
/// Please refer to `accept_async()` for more details.
pub async fn accept_async_with_config<S>(
    stream: S,
    config: Option<WebSocketConfig>,
) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    accept_hdr_async_with_config(stream, NoCallback, config).await
}

/// Accepts a new WebSocket connection with the provided stream.
///
/// This function does the same as `accept_async()` but accepts an extra callback
/// for header processing. The callback receives headers of the incoming
/// requests and is able to add extra headers to the reply.
pub async fn accept_hdr_async<S, C>(stream: S, callback: C) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
    C: Callback + Unpin,
{
    accept_hdr_async_with_config(stream, callback, None).await
}

/// The same as `accept_hdr_async()` but the one can specify a websocket configuration.
/// Please refer to `accept_hdr_async()` for more details.
pub async fn accept_hdr_async_with_config<S, C>(
    stream: S,
    callback: C,
    config: Option<WebSocketConfig>,
) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
    C: Callback + Unpin,
{
    let f = handshake::server_handshake(stream, move |allow_std| {
        server::accept_hdr_with_config(allow_std, callback, config)
    });
    f.await.map_err(|e| {
        WsError::Io(std::io::Error::new(
            std::io::ErrorKind::Other,
            e.to_string(),
        ))
    })
}

/// A wrapper around an underlying raw stream which implements the WebSocket
/// protocol.
///
/// A `WebSocketStream<S>` represents a handshake that has been completed
/// successfully and both the server and the client are ready for receiving
/// and sending data. Message from a `WebSocketStream<S>` are accessible
/// through the respective `Stream` and `Sink`. Check more information about
/// them in `futures-rs` crate documentation or have a look on the examples
/// and unit tests for this crate.
#[derive(Debug)]
pub struct WebSocketStream<S> {
    inner: WebSocket<AllowStd<S>>,
}

impl<S> WebSocketStream<S> {
    /// Convert a raw socket into a WebSocketStream without performing a
    /// handshake.
    pub async fn from_raw_socket(stream: S, role: Role, config: Option<WebSocketConfig>) -> Self
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake::without_handshake(stream, move |allow_std| {
            WebSocket::from_raw_socket(allow_std, role, config)
        })
        .await
    }

    /// Convert a raw socket into a WebSocketStream without performing a
    /// handshake.
    pub async fn from_partially_read(
        stream: S,
        part: Vec<u8>,
        role: Role,
        config: Option<WebSocketConfig>,
    ) -> Self
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake::without_handshake(stream, move |allow_std| {
            WebSocket::from_partially_read(allow_std, part, role, config)
        })
        .await
    }

    pub(crate) fn new(ws: WebSocket<AllowStd<S>>) -> Self {
        WebSocketStream { inner: ws }
    }

    fn with_context<F, R>(&mut self, ctx: Option<(ContextWaker, &mut Context<'_>)>, f: F) -> R
    where
        S: Unpin,
        F: FnOnce(&mut WebSocket<AllowStd<S>>) -> R,
        AllowStd<S>: Read + Write,
    {
        trace!("{}:{} WebSocketStream.with_context", file!(), line!());
        if let Some((kind, ctx)) = ctx {
            self.inner.get_mut().set_waker(kind, &ctx.waker());
        }
        f(&mut self.inner)
    }

    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        &self.inner.get_ref().get_ref()
    }

    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        self.inner.get_mut().get_mut()
    }

    /// Close the underlying web socket
    pub async fn close(&mut self, msg: Option<CloseFrame<'_>>) -> Result<(), WsError>
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        let msg = msg.map(|msg| msg.into_owned());
        self.send(Message::Close(msg)).await
    }
}

impl<T> Stream for WebSocketStream<T>
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Item = Result<Message, WsError>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        trace!("{}:{} Stream.poll_next", file!(), line!());
        match futures_util::ready!(self.with_context(Some((ContextWaker::Read, cx)), |s| {
            trace!(
                "{}:{} Stream.with_context poll_next -> read_message()",
                file!(),
                line!()
            );
            cvt(s.read_message())
        })) {
            Ok(v) => Poll::Ready(Some(Ok(v))),
            Err(WsError::AlreadyClosed) | Err(WsError::ConnectionClosed) => Poll::Ready(None),
            Err(e) => Poll::Ready(Some(Err(e))),
        }
    }
}

impl<T> Sink<Message> for WebSocketStream<T>
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Error = WsError;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        (*self).with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.write_pending()))
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        match (*self).with_context(None, |s| s.write_message(item)) {
            Ok(()) => Ok(()),
            Err(::tungstenite::Error::Io(ref err))
                if err.kind() == std::io::ErrorKind::WouldBlock =>
            {
                // the message was accepted and queued
                // isn't an error.
                Ok(())
            }
            Err(e) => {
                debug!("websocket start_send error: {}", e);
                Err(e)
            }
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        (*self).with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.write_pending()))
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        match (*self).with_context(Some((ContextWaker::Write, cx)), |s| s.close(None)) {
            Ok(()) => Poll::Ready(Ok(())),
            Err(::tungstenite::Error::ConnectionClosed) => Poll::Ready(Ok(())),
            Err(err) => {
                debug!("websocket close error: {}", err);
                Poll::Ready(Err(err))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::compat::AllowStd;
    #[cfg(feature = "connect")]
    use crate::connect::encryption::AutoStream;
    use crate::WebSocketStream;
    use std::io::{Read, Write};
    use tokio::io::{AsyncReadExt, AsyncWriteExt};

    fn is_read<T: Read>() {}
    fn is_write<T: Write>() {}
    fn is_async_read<T: AsyncReadExt>() {}
    fn is_async_write<T: AsyncWriteExt>() {}
    fn is_unpin<T: Unpin>() {}

    #[test]
    fn web_socket_stream_has_traits() {
        is_read::<AllowStd<tokio::net::TcpStream>>();
        is_write::<AllowStd<tokio::net::TcpStream>>();

        #[cfg(feature = "connect")]
        is_async_read::<AutoStream<tokio::net::TcpStream>>();
        #[cfg(feature = "connect")]
        is_async_write::<AutoStream<tokio::net::TcpStream>>();

        is_unpin::<WebSocketStream<tokio::net::TcpStream>>();
        #[cfg(feature = "connect")]
        is_unpin::<WebSocketStream<AutoStream<tokio::net::TcpStream>>>();
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use unique::Unique;
use std::marker::PhantomData;
use std::ptr::{self};
use std::ffi::{CStr,CString};
use std::path::Path;
use std::slice;
use std::ops::Deref;
use std::mem::transmute;
use std::str;
use std::fmt;
use self::Error::*;

mod raw;
mod unique;

const PCAP_ERROR_NOT_ACTIVATED: i32 = -3;

/// An error received from pcap
#[derive(Debug)]
pub enum Error {
    MalformedError(str::Utf8Error),
    PcapError(String)
}

impl Error {
    fn new<T>(ptr: *const libc::c_char) -> Result<T, Error> {
        Err(PcapError(try!(cstr_to_string(ptr))))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MalformedError(e) => {
                write!(f, "pcap returned an error that was not encoded properly: {}", e)
            },
            PcapError(ref e) => {
                write!(f, "pcap error: {}", e)
            }
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            MalformedError(..) => "error message from pcap is invalid",
            PcapError(..) => "pcap FFI error"
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            MalformedError(ref e) => Some(e),
            _ => None
        }
    }
}

impl From<str::Utf8Error> for Error {
    fn from(obj: str::Utf8Error) -> Error {
        MalformedError(obj)
    }
}

#[derive(Debug)]
/// A network device as returned from `Devices::list_all()`.
pub struct Device {
    pub name: String,
    pub desc: Option<String>
}

impl Device {
    /// Returns the default Device suitable for captures according to pcap_lookupdev,
    /// or an error from pcap.
    pub fn lookup() -> Result<Device, Error> {
        let mut errbuf = [0i8; 256];

        unsafe {
            let default_name = raw::pcap_lookupdev(errbuf.as_mut_ptr());

            if default_name.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            Ok(Device {
                name: try!(cstr_to_string(default_name)),
                desc: None
            })
        }
    }

    /// Returns a vector of `Device`s known by pcap.
    pub fn list() -> Result<Vec<Device>, Error> {
        unsafe {
            let mut errbuf = [0i8; 256];
            let mut dev_buf: *mut raw::Struct_pcap_if = ptr::null_mut();
            let mut ret = vec![];

            match raw::pcap_findalldevs(&mut dev_buf, errbuf.as_mut_ptr()) {
                0 => {
                    let mut cur = dev_buf;

                    while !cur.is_null() {
                        ret.push(Device {
                            name: cstr_to_string((&*cur).name).unwrap(),
                            desc: {
                                if !(&*cur).description.is_null() {
                                    Some(cstr_to_string((&*cur).description).unwrap())
                                } else {
                                    None
                                }
                            }
                        });

                        cur = (&*cur).next;
                    }

                    raw::pcap_freealldevs(dev_buf);

                    Ok(ret)
                },
                _ => {
                    Error::new(errbuf.as_ptr())
                }
            }
        }
    }
}

impl<'a> Into<Device> for &'a str {
    fn into(self) -> Device {
        Device {
            name: self.into(),
            desc: None
        }
    }
}

/// This is a datalink link type returned from pcap.
#[derive(Debug)]
pub struct Linktype(pub i32);

impl Linktype {
    /// Gets the name of the link type, such as EN10MB
    pub fn get_name(&self) -> Result<String, Error> {
        unsafe {
            Ok(try!(cstr_to_string(raw::pcap_datalink_val_to_name(self.0))))
        }
    }

    /// Gets the description of a link type.
    pub fn get_description(&self) -> Result<String, Error> {
        unsafe {
            Ok(try!(cstr_to_string(raw::pcap_datalink_val_to_description(self.0))))
        }
    }
}

/// Represents a packet returned from pcap. This can be dereferenced to access
/// the underlying packet `[u8]` slice.
pub struct Packet<'a> {
    header: &'a raw::Struct_pcap_pkthdr,
    data: &'a libc::c_uchar
}

impl<'b> Deref for Packet<'b> {
    type Target = [u8];

    fn deref<'a>(&'a self) -> &'a [u8] {
        unsafe {
            slice::from_raw_parts(self.data, self.header.caplen as usize)
        }
    }
}

impl<'a> fmt::Debug for Packet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.deref().fmt(f)
    }
}

/// Phantom type representing an inactive capture handle.
pub enum Inactive {}
/// Phantom type representing an active capture handle. Implements `Activated`.
pub enum Active {}
/// Phantom type representing an offline capture handle, from a pcap dump file.
/// Implements `Activated`.
pub enum Offline {}

// we do this because we cannot do impl<T> Capture<T> and provide specific return results
// without tripping up type ambiguities at the callsite.
#[doc(hidden)]
pub enum All {}

trait Activated {}

impl Activated for Active {}
impl Activated for Offline {}

/// This is a pcap capture handle which is an abstraction over the `pcap_t` provided by pcap.
/// There are many ways to instantiate and interact with a pcap handle, so phantom types are
/// used to express these behaviors.
///
/// **`Capture<Inactive>`** is created via `Capture::from_device()`. This handle is inactive,
/// so you cannot (yet) obtain packets from it. However, you can configure things like the
/// buffer size, snaplen, timeout, and promiscuity before you activate it.
///
/// **`Capture<Active>`** is created by calling `.open()` on a `Capture<Inactive>`. This
/// activates the capture handle, allowing you to get packets with `.next()` or apply filters
/// with `.filter()`.
///
/// **`Capture<Offline>`** is created via `Capture::from_file()`. This allows you to read a
/// pcap format dump file as if you were opening an interface -- very useful for testing or
/// analysis.
///
/// # Example:
///
/// ```ignore
/// let cap = Capture::from_device(Device::lookup().unwrap()) // open the "default" interface
///               .unwrap() // assume the device exists and we are authorized to open it
///               .open() // activate the handle
///               .unwrap(); // assume activation worked
///
/// while let Some(packet) = cap.next() {
///     println!("received packet! {:?}", packet);
/// }
/// ```
pub struct Capture<T> {
    handle: Unique<raw::pcap_t>,
    _marker: PhantomData<T>
}

impl Capture<All> {
    /// Opens a capture handle for a device. The handle is inactive, but can be activated
    /// via `.open()`. You can pass a `Device` or an `&str` device name here.
    pub fn from_device<D: Into<Device>>(device: D) -> Result<Capture<Inactive>, Error> {
        let device: Device = device.into();
        let name = CString::new(device.name).unwrap();
        let mut errbuf = [0i8; 256];

        unsafe {
            let handle = raw::pcap_create(name.as_ptr(), errbuf.as_mut_ptr());
            if handle.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            Ok(Capture {
                handle: Unique::new(handle),
                _marker: PhantomData
            })
        }
    }

    /// Opens an offline capture handle from a pcap dump file, given a path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Capture<Offline>, Error> {
        let name = CString::new(path.as_ref().to_str().unwrap()).unwrap();
        let mut errbuf = [0i8; 256];

        unsafe {
            let handle = raw::pcap_open_offline(name.as_ptr(), errbuf.as_mut_ptr());
            if handle.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            Ok(Capture {
                handle: Unique::new(handle),
                _marker: PhantomData
            })
        }
    }
}

impl Capture<Inactive> {
    /// Activates an inactive capture created from `Capture::from_device()` or returns
    /// an error.
    pub fn open(self) -> Result<Capture<Active>, Error> {
        unsafe {
            let cap = transmute::<Capture<Inactive>, Capture<Active>>(self);

            if 0 != raw::pcap_activate(*cap.handle) {
                return Error::new(raw::pcap_geterr(*cap.handle));
            }

            Ok(cap)
        }
    }

    /// Set the read timeout for the Capture. By default, this is 0, so it will block
    /// indefinitely.
    pub fn timeout(self, ms: i32) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_timeout(*self.handle, ms);
            self
        }
    }

    /// Set promiscuous mode on or off. By default, this is off.
    pub fn promisc(self, to: bool) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_promisc(*self.handle, if to {1} else {0});
            self
        }
    }

    /// Set rfmon mode on or off. The default is maintained by pcap.
    pub fn rfmon(self, to: bool) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_rfmon(*self.handle, if to {1} else {0});
            self
        }
    }

    /// Set the buffer size for incoming packet data.
    ///
    /// The default is 1000000. This should always be larger than the snaplen.
    pub fn buffer_size(self, to: i32) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_buffer_size(*self.handle, to);
            self
        }
    }

    /// Set the snaplen size (the maximum length of a packet captured into the buffer).
    /// Useful if you only want certain headers, but not the entire packet.
    ///
    /// The default is 65535
    pub fn snaplen(self, to: i32) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_snaplen(*self.handle, to);
            self
        }
    }
}

///# Activated captures include `Capture<Active>` and `Capture<Offline>`.
impl<T: Activated> Capture<T> {
    /// List the datalink types that this captured device supports.
    pub fn list_datalinks(&mut self) -> Result<Vec<Linktype>, Error> {
        unsafe {
            let mut links: *mut i32 = ptr::null_mut();

            let num = raw::pcap_list_datalinks(*self.handle, &mut links);

            if num == PCAP_ERROR_NOT_ACTIVATED {
                raw::pcap_free_datalinks(links);
                panic!("It should not be possible to run list_datalinks on a Capture that is not activated, please report this bug!")
            } else if num < 0 {
                raw::pcap_free_datalinks(links);
                Error::new(raw::pcap_geterr(*self.handle))
            } else {
                let slice = slice::from_raw_parts(links, num as usize).iter().map(|&a| Linktype(a)).collect();
                raw::pcap_free_datalinks(links);

                Ok(slice)
            }
        }
    }

    /// Set the datalink type for the current capture handle.
    pub fn set_datalink(&mut self, linktype: Linktype) -> Result<(), Error> {
        unsafe {
            match raw::pcap_set_datalink(*self.handle, linktype.0) {
                0 => {
                    Ok(())
                },
                _ => {
                    Error::new(raw::pcap_geterr(*self.handle))
                }
            }
        }
    }

    /// Get the current datalink type for this capture handle.
    pub fn get_datalink(&mut self) -> Linktype {
        unsafe {
            match raw::pcap_datalink(*self.handle) {
                PCAP_ERROR_NOT_ACTIVATED => {
                    panic!("It should not be possible to run get_datalink on a Capture that is not activated, please report this bug!");
                },
                lt => {
                    Linktype(lt)
                }
            }
        }
    }

    /// Blocks until a packet is returned from the capture handle or an error occurs.
    ///
    /// pcap captures packets and places them into a buffer which this function reads
    /// from. This buffer has a finite length, so if the buffer fills completely new
    /// packets will be discarded temporarily. This means that in realtime situations,
    /// you probably want to minimize the time between calls of this next() method.
    pub fn next<'a>(&'a mut self) -> Option<Packet<'a>> {
        unsafe {
            let mut header: *mut raw::Struct_pcap_pkthdr = ptr::null_mut();
            let mut packet: *const libc::c_uchar = ptr::null();
            match raw::pcap_next_ex(*self.handle, &mut header, &mut packet) {
                1 => {
                    // packet was read without issue
                    Some(Packet {
                        header: &*header,
                        data: &*packet
                    })
                },
                _ => {
                    None
                }
            }
        }
    }

    /// Adds a filter to the capture using the given BPF program string. Internally
    /// this is compiled using `pcap_compile()`.
    ///
    /// See http://biot.com/capstats/bpf.html for more information about this syntax.
    pub fn filter(&mut self, program: &str) -> Result<(), Error> {
        let program = CString::new(program).unwrap();

        unsafe {
            let mut bpf_program: raw::Struct_bpf_program = Default::default();

            if -1 == raw::pcap_compile(*self.handle, &mut bpf_program, program.as_ptr(), 0, 0) {
                return Error::new(raw::pcap_geterr(*self.handle));
            }

            if -1 == raw::pcap_setfilter(*self.handle, &mut bpf_program) {
                raw::pcap_freecode(&mut bpf_program);
                return Error::new(raw::pcap_geterr(*self.handle));
            }

            raw::pcap_freecode(&mut bpf_program);
            Ok(())
        }
    }
}

impl<T> Drop for Capture<T> {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_close(*self.handle)
        }
    }
}

fn cstr_to_string(ptr: *const libc::c_char) -> Result<String, str::Utf8Error> {
    Ok(try!(str::from_utf8(unsafe{CStr::from_ptr(ptr)}.to_bytes())).to_string())
}
<commit_msg>More documentation improvements.<commit_after>extern crate libc;

use unique::Unique;
use std::marker::PhantomData;
use std::ptr;
use std::ffi::{CStr,CString};
use std::path::Path;
use std::slice;
use std::ops::Deref;
use std::mem::transmute;
use std::str;
use std::fmt;
use self::Error::*;

mod raw;
mod unique;

const PCAP_ERROR_NOT_ACTIVATED: i32 = -3;

/// An error received from pcap
#[derive(Debug)]
pub enum Error {
    MalformedError(str::Utf8Error),
    PcapError(String)
}

impl Error {
    fn new<T>(ptr: *const libc::c_char) -> Result<T, Error> {
        Err(PcapError(try!(cstr_to_string(ptr))))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MalformedError(e) => {
                write!(f, "pcap returned an error that was not encoded properly: {}", e)
            },
            PcapError(ref e) => {
                write!(f, "pcap error: {}", e)
            }
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            MalformedError(..) => "error message from pcap is invalid",
            PcapError(..) => "pcap FFI error"
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            MalformedError(ref e) => Some(e),
            _ => None
        }
    }
}

impl From<str::Utf8Error> for Error {
    fn from(obj: str::Utf8Error) -> Error {
        MalformedError(obj)
    }
}

#[derive(Debug)]
/// A network device name and (potentially) pcap's description of it.
pub struct Device {
    pub name: String,
    pub desc: Option<String>
}

impl Device {
    /// Returns the default Device suitable for captures according to pcap_lookupdev,
    /// or an error from pcap.
    pub fn lookup() -> Result<Device, Error> {
        let mut errbuf = [0i8; 256];

        unsafe {
            let default_name = raw::pcap_lookupdev(errbuf.as_mut_ptr());

            if default_name.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            Ok(Device {
                name: try!(cstr_to_string(default_name)),
                desc: None
            })
        }
    }

    /// Returns a vector of `Device`s known by pcap via pcap_findalldevs.
    pub fn list() -> Result<Vec<Device>, Error> {
        unsafe {
            let mut errbuf = [0i8; 256];
            let mut dev_buf: *mut raw::Struct_pcap_if = ptr::null_mut();
            let mut ret = vec![];

            match raw::pcap_findalldevs(&mut dev_buf, errbuf.as_mut_ptr()) {
                0 => {
                    let mut cur = dev_buf;

                    while !cur.is_null() {
                        ret.push(Device {
                            name: cstr_to_string((&*cur).name).unwrap(),
                            desc: {
                                if !(&*cur).description.is_null() {
                                    Some(cstr_to_string((&*cur).description).unwrap())
                                } else {
                                    None
                                }
                            }
                        });

                        cur = (&*cur).next;
                    }

                    raw::pcap_freealldevs(dev_buf);

                    Ok(ret)
                },
                _ => {
                    Error::new(errbuf.as_ptr())
                }
            }
        }
    }
}

impl<'a> Into<Device> for &'a str {
    fn into(self) -> Device {
        Device {
            name: self.into(),
            desc: None
        }
    }
}

/// This is a datalink link type.
///
/// As an example, `Linktype(1)` is ethernet. A full list of linktypes is available
/// [here](http://www.tcpdump.org/linktypes.html).
#[derive(Debug)]
pub struct Linktype(pub i32);

impl Linktype {
    /// Gets the name of the link type, such as EN10MB
    pub fn get_name(&self) -> Result<String, Error> {
        unsafe {
            Ok(try!(cstr_to_string(raw::pcap_datalink_val_to_name(self.0))))
        }
    }

    /// Gets the description of a link type.
    pub fn get_description(&self) -> Result<String, Error> {
        unsafe {
            Ok(try!(cstr_to_string(raw::pcap_datalink_val_to_description(self.0))))
        }
    }
}

/// Represents a packet returned from pcap. This can be dereferenced to access
/// the underlying packet `[u8]` slice.
pub struct Packet<'a> {
    header: &'a raw::Struct_pcap_pkthdr,
    data: &'a libc::c_uchar
}

impl<'b> Deref for Packet<'b> {
    type Target = [u8];

    fn deref<'a>(&'a self) -> &'a [u8] {
        unsafe {
            slice::from_raw_parts(self.data, self.header.caplen as usize)
        }
    }
}

impl<'a> fmt::Debug for Packet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.deref().fmt(f)
    }
}

/// Phantom type representing an inactive capture handle.
pub enum Inactive {}
/// Phantom type representing an active capture handle. Implements `Activated`.
pub enum Active {}
/// Phantom type representing an offline capture handle, from a pcap dump file.
/// Implements `Activated`.
pub enum Offline {}

// we do this because we cannot do impl<T> Capture<T> and provide specific return results
// without tripping up type ambiguities at the callsite.
#[doc(hidden)]
pub enum All {}

trait Activated {}

impl Activated for Active {}
impl Activated for Offline {}

/// This is a pcap capture handle which is an abstraction over the `pcap_t` provided by pcap.
/// There are many ways to instantiate and interact with a pcap handle, so phantom types are
/// used to express these behaviors.
///
/// **`Capture<Inactive>`** is created via `Capture::from_device()`. This handle is inactive,
/// so you cannot (yet) obtain packets from it. However, you can configure things like the
/// buffer size, snaplen, timeout, and promiscuity before you activate it.
///
/// **`Capture<Active>`** is created by calling `.open()` on a `Capture<Inactive>`. This
/// activates the capture handle, allowing you to get packets with `.next()` or apply filters
/// with `.filter()`.
///
/// **`Capture<Offline>`** is created via `Capture::from_file()`. This allows you to read a
/// pcap format dump file as if you were opening an interface -- very useful for testing or
/// analysis.
///
/// # Example:
///
/// ```ignore
/// let cap = Capture::from_device(Device::lookup().unwrap()) // open the "default" interface
///               .unwrap() // assume the device exists and we are authorized to open it
///               .open() // activate the handle
///               .unwrap(); // assume activation worked
///
/// while let Some(packet) = cap.next() {
///     println!("received packet! {:?}", packet);
/// }
/// ```
pub struct Capture<T> {
    handle: Unique<raw::pcap_t>,
    _marker: PhantomData<T>
}

impl Capture<All> {
    /// Opens a capture handle for a device. The handle is inactive, but can be activated
    /// via `.open()`. You can pass a `Device` or an `&str` device name here.
    pub fn from_device<D: Into<Device>>(device: D) -> Result<Capture<Inactive>, Error> {
        let device: Device = device.into();
        let name = CString::new(device.name).unwrap();
        let mut errbuf = [0i8; 256];

        unsafe {
            let handle = raw::pcap_create(name.as_ptr(), errbuf.as_mut_ptr());
            if handle.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            Ok(Capture {
                handle: Unique::new(handle),
                _marker: PhantomData
            })
        }
    }

    /// Opens an offline capture handle from a pcap dump file, given a path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Capture<Offline>, Error> {
        let name = CString::new(path.as_ref().to_str().unwrap()).unwrap();
        let mut errbuf = [0i8; 256];

        unsafe {
            let handle = raw::pcap_open_offline(name.as_ptr(), errbuf.as_mut_ptr());
            if handle.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            Ok(Capture {
                handle: Unique::new(handle),
                _marker: PhantomData
            })
        }
    }
}

impl Capture<Inactive> {
    /// Activates an inactive capture created from `Capture::from_device()` or returns
    /// an error.
    pub fn open(self) -> Result<Capture<Active>, Error> {
        unsafe {
            let cap = transmute::<Capture<Inactive>, Capture<Active>>(self);

            if 0 != raw::pcap_activate(*cap.handle) {
                return Error::new(raw::pcap_geterr(*cap.handle));
            }

            Ok(cap)
        }
    }

    /// Set the read timeout for the Capture. By default, this is 0, so it will block
    /// indefinitely.
    pub fn timeout(self, ms: i32) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_timeout(*self.handle, ms);
            self
        }
    }

    /// Set promiscuous mode on or off. By default, this is off.
    pub fn promisc(self, to: bool) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_promisc(*self.handle, if to {1} else {0});
            self
        }
    }

    /// Set rfmon mode on or off. The default is maintained by pcap.
    pub fn rfmon(self, to: bool) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_rfmon(*self.handle, if to {1} else {0});
            self
        }
    }

    /// Set the buffer size for incoming packet data.
    ///
    /// The default is 1000000. This should always be larger than the snaplen.
    pub fn buffer_size(self, to: i32) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_buffer_size(*self.handle, to);
            self
        }
    }

    /// Set the snaplen size (the maximum length of a packet captured into the buffer).
    /// Useful if you only want certain headers, but not the entire packet.
    ///
    /// The default is 65535
    pub fn snaplen(self, to: i32) -> Capture<Inactive> {
        unsafe {
            raw::pcap_set_snaplen(*self.handle, to);
            self
        }
    }
}

///# Activated captures include `Capture<Active>` and `Capture<Offline>`.
impl<T: Activated> Capture<T> {
    /// List the datalink types that this captured device supports.
    pub fn list_datalinks(&mut self) -> Result<Vec<Linktype>, Error> {
        unsafe {
            let mut links: *mut i32 = ptr::null_mut();

            let num = raw::pcap_list_datalinks(*self.handle, &mut links);

            if num == PCAP_ERROR_NOT_ACTIVATED {
                raw::pcap_free_datalinks(links);
                panic!("It should not be possible to run list_datalinks on a Capture that is not activated, please report this bug!")
            } else if num < 0 {
                raw::pcap_free_datalinks(links);
                Error::new(raw::pcap_geterr(*self.handle))
            } else {
                let slice = slice::from_raw_parts(links, num as usize).iter().map(|&a| Linktype(a)).collect();
                raw::pcap_free_datalinks(links);

                Ok(slice)
            }
        }
    }

    /// Set the datalink type for the current capture handle.
    pub fn set_datalink(&mut self, linktype: Linktype) -> Result<(), Error> {
        unsafe {
            match raw::pcap_set_datalink(*self.handle, linktype.0) {
                0 => {
                    Ok(())
                },
                _ => {
                    Error::new(raw::pcap_geterr(*self.handle))
                }
            }
        }
    }

    /// Get the current datalink type for this capture handle.
    pub fn get_datalink(&mut self) -> Linktype {
        unsafe {
            match raw::pcap_datalink(*self.handle) {
                PCAP_ERROR_NOT_ACTIVATED => {
                    panic!("It should not be possible to run get_datalink on a Capture that is not activated, please report this bug!");
                },
                lt => {
                    Linktype(lt)
                }
            }
        }
    }

    /// Blocks until a packet is returned from the capture handle or an error occurs.
    ///
    /// pcap captures packets and places them into a buffer which this function reads
    /// from. This buffer has a finite length, so if the buffer fills completely new
    /// packets will be discarded temporarily. This means that in realtime situations,
    /// you probably want to minimize the time between calls of this next() method.
    pub fn next<'a>(&'a mut self) -> Option<Packet<'a>> {
        unsafe {
            let mut header: *mut raw::Struct_pcap_pkthdr = ptr::null_mut();
            let mut packet: *const libc::c_uchar = ptr::null();
            match raw::pcap_next_ex(*self.handle, &mut header, &mut packet) {
                1 => {
                    // packet was read without issue
                    Some(Packet {
                        header: &*header,
                        data: &*packet
                    })
                },
                _ => {
                    None
                }
            }
        }
    }

    /// Adds a filter to the capture using the given BPF program string. Internally
    /// this is compiled using `pcap_compile()`.
    ///
    /// See http://biot.com/capstats/bpf.html for more information about this syntax.
    pub fn filter(&mut self, program: &str) -> Result<(), Error> {
        let program = CString::new(program).unwrap();

        unsafe {
            let mut bpf_program: raw::Struct_bpf_program = Default::default();

            if -1 == raw::pcap_compile(*self.handle, &mut bpf_program, program.as_ptr(), 0, 0) {
                return Error::new(raw::pcap_geterr(*self.handle));
            }

            if -1 == raw::pcap_setfilter(*self.handle, &mut bpf_program) {
                raw::pcap_freecode(&mut bpf_program);
                return Error::new(raw::pcap_geterr(*self.handle));
            }

            raw::pcap_freecode(&mut bpf_program);
            Ok(())
        }
    }
}

impl<T> Drop for Capture<T> {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_close(*self.handle)
        }
    }
}

fn cstr_to_string(ptr: *const libc::c_char) -> Result<String, str::Utf8Error> {
    Ok(try!(str::from_utf8(unsafe{CStr::from_ptr(ptr)}.to_bytes())).to_string())
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as extensions to the
//! MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of the SemVer
//! spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard libraries. The two are
//! not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine which versions of
//! packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse`
//! method:
//!
//! ```{rust}
//! use semver::version;
//!
//! assert!(version::parse("1.2.3") == Ok(version::Version {
//!    major: 1u32,
//!    minor: 2u32,
//!    patch: 3u32,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators to compare them:
//!
//! ```{rust}
//! use semver::version;
//!
//! assert!(version::parse("1.2.3-alpha")  != version::parse("1.2.3-beta"));
//! assert!(version::parse("1.2.3-alpha2") >  version::parse("1.2.0"));
//! ```
//!
//! ## Ranges
//!
//! The `semver` crate also provides a `range` module, which allows you to do more
//! complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than or
//! equal to 1.0.0:
//!
//! ```{rust}
//! use semver::version;
//! use semver::range;
//!
//! let r = range::VersionReq::parse(">= 1.0.0").unwrap();
//! let v = version::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```

#![crate_name = "semver"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]
#![feature(default_type_params)]
#![feature(macro_rules)]

/// SemVer-compliant versions.
pub mod version;

/// advanced version comparisons
pub mod range;
<commit_msg>Re-export rather than make directly private.<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as extensions to the
//! MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of the SemVer
//! spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard libraries. The two are
//! not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine which versions of
//! packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse`
//! method:
//!
//! ```{rust}
//! use semver;
//!
//! assert!(semver::parse("1.2.3") == Ok(semver::Version {
//!    major: 1u32,
//!    minor: 2u32,
//!    patch: 3u32,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators to compare them:
//!
//! ```{rust}
//! use semver;
//!
//! assert!(semver::parse("1.2.3-alpha")  != semver::parse("1.2.3-beta"));
//! assert!(semver::parse("1.2.3-alpha2") >  semver::parse("1.2.0"));
//! ```
//!
//! ## Ranges
//!
//! The `semver` crate also provides a `range` module, which allows you to do more
//! complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than or
//! equal to 1.0.0:
//!
//! ```{rust}
//! use semver;
//!
//! let r = semver::VersionReq::parse(">= 1.0.0").unwrap();
//! let v = semver::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```

#![crate_name = "semver"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]
#![feature(default_type_params)]
#![feature(macro_rules)]

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{
    Version,
    parse,
    Identifier,
    ParseError,
};

pub use range::VersionReq;

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod range;

<|endoftext|>


<commit_before>#![feature(macro_rules, phase, default_type_params, slicing_syntax, globs)]
#![deny(missing_docs)]
#![deny(warnings)]
#![experimental]

//! # Hyper
//! Hyper is a fast, modern HTTP implementation written in and for Rust. It
//! is a low-level typesafe abstraction over raw HTTP, providing an elegant
//! layer over "stringly-typed" HTTP.
//!
//! Hyper offers both an HTTP/S client an HTTP server which can be used to drive
//! complex web applications written entirely in Rust.
//!
//! ## Internal Design
//!
//! Hyper is designed as a relatively low-level wrapped over raw HTTP. It should
//! allow the implementation of higher-level abstractions with as little pain as
//! possible, and should not irrevocably hide any information from its users.
//!
//! ### Common Functionality
//!
//! Functionality and code shared between the Server and Client implementations can
//! be found in `src` directly - this includes `NetworkStream`s, `Method`s,
//! `StatusCode`, and so on.
//!
//! #### Methods
//!
//! Methods are represented as a single `enum` to remain as simple as possible.
//! Extension Methods are represented as raw `String`s. A method's safety and
//! idempotence can be accessed using the `safe` and `idempotent` methods.
//!
//! #### StatusCode
//!
//! Status codes are also represented as a single, exhaustive, `enum`. This
//! representation is efficient, typesafe, and ergonomic as it allows the use of
//! `match` to disambiguate known status codes.
//!
//! #### Headers
//!
//! Hyper's header representation is likely the most complex API exposed by Hyper.
//!
//! Hyper's headers are an abstraction over an internal `HashMap` and provides a
//! typesafe API for interacting with headers that does not rely on the use of
//! "string-typing."
//!
//! Each HTTP header in Hyper has an associated type and implementation of the
//! `Header` trait, which defines an HTTP headers name as a string, how to parse
//! that header, and how to format that header.
//!
//! Headers are then parsed from the string representation lazily when the typed
//! representation of a header is requested and formatted back into their string
//! representation when headers are written back to the client.
//!
//! #### NetworkStream and NetworkAcceptor
//!
//! These are found in `src/net.rs` and define the interface that acceptors and
//! streams must fulfill for them to be used within Hyper. They are by and large
//! internal tools and you should only need to mess around with them if you want to
//! mock or replace `TcpStream` and `TcpAcceptor`.
//!
//! ### Server
//!
//! Server-specific functionality, such as `Request` and `Response`
//! representations, are found in in `src/server`.
//!
//! #### Handler + Server
//!
//! A `Handler` in Hyper accepts a `Request` and `Response`. This is where
//! user-code can handle each connection. The server accepts connections in a
//! task pool with a customizable number of threads, and passes the Request /
//! Response to the handler.
//!
//! #### Request
//!
//! An incoming HTTP Request is represented as a struct containing
//! a `Reader` over a `NetworkStream`, which represents the body, headers, a remote
//! address, an HTTP version, and a `Method` - relatively standard stuff.
//!
//! `Request` implements `Reader` itself, meaning that you can ergonomically get
//! the body out of a `Request` using standard `Reader` methods and helpers.
//!
//! #### Response
//!
//! An outgoing HTTP Response is also represented as a struct containing a `Writer`
//! over a `NetworkStream` which represents the Response body in addition to
//! standard items such as the `StatusCode` and HTTP version. `Response`'s `Writer`
//! implementation provides a streaming interface for sending data over to the
//! client.
//!
//! One of the traditional problems with representing outgoing HTTP Responses is
//! tracking the write-status of the Response - have we written the status-line,
//! the headers, the body, etc.? Hyper tracks this information statically using the
//! type system and prevents you, using the type system, from writing headers after
//! you have started writing to the body or vice versa.
//!
//! Hyper does this through a phantom type parameter in the definition of Response,
//! which tracks whether you are allowed to write to the headers or the body. This
//! phantom type can have two values `Fresh` or `Streaming`, with `Fresh`
//! indicating that you can write the headers and `Streaming` indicating that you
//! may write to the body, but not the headers.
//!
//! ### Client
//!
//! Client-specific functionality, such as `Request` and `Response`
//! representations, are found in `src/client`.
//!
//! #### Request
//!
//! An outgoing HTTP Request is represented as a struct containing a `Writer` over
//! a `NetworkStream` which represents the Request body in addition to the standard
//! information such as headers and the request method.
//!
//! Outgoing Requests track their write-status in almost exactly the same way as
//! outgoing HTTP Responses do on the Server, so we will defer to the explanation
//! in the documentation for sever Response.
//!
//! Requests expose an efficient streaming interface instead of a builder pattern,
//! but they also provide the needed interface for creating a builder pattern over
//! the API exposed by core Hyper.
//!
//! #### Response
//!
//! Incoming HTTP Responses are represented as a struct containing a `Reader` over
//! a `NetworkStream` and contain headers, a status, and an http version. They
//! implement `Reader` and can be read to get the data out of a `Response`.
//!

extern crate "rustc-serialize" as serialize;
extern crate time;
extern crate url;
extern crate openssl;
#[phase(plugin,link)] extern crate log;
#[cfg(test)] extern crate test;
extern crate "unsafe-any" as uany;
extern crate cookie;
extern crate mucell;

pub use std::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr, Port};
pub use mimewrapper::mime;
pub use url::Url;
pub use client::Client;
pub use method::Method::{Get, Head, Post, Delete};
pub use status::StatusCode::{Ok, BadRequest, NotFound};
pub use server::Server;

use std::fmt;
use std::error::{Error, FromError};
use std::io::IoError;

use std::rt::backtrace;

use self::HttpError::{HttpMethodError, HttpUriError, HttpVersionError,
                      HttpHeaderError, HttpStatusError, HttpIoError};

macro_rules! todo(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) {
        format_args!(|args| log!(5, "TODO: {}", args), $($arg)*)
    })
);

#[allow(dead_code)]
struct Trace;

impl fmt::Show for Trace {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let _ = backtrace::write(fmt);
        Result::Ok(())
    }
}

macro_rules! trace(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) {
        format_args!(|args| log!(5, "{}\n{}", args, ::Trace), $($arg)*)
    })
);

macro_rules! inspect(
    ($name:expr, $value:expr) => ({
        let v = $value;
        debug!("inspect: {} = {}", $name, v);
        v
    })
);

#[cfg(test)]
#[macro_escape]
mod mock;

pub mod client;
pub mod method;
pub mod header;
pub mod http;
pub mod net;
pub mod server;
pub mod status;
pub mod uri;
pub mod version;

mod mimewrapper {
    /// Re-exporting the mime crate, for convenience.
    extern crate mime;
}

/// Result type often returned from methods that can have `HttpError`s.
pub type HttpResult<T> = Result<T, HttpError>;

/// A set of errors that can occur parsing HTTP streams.
#[deriving(Show, PartialEq, Clone)]
pub enum HttpError {
    /// An invalid `Method`, such as `GE,T`.
    HttpMethodError,
    /// An invalid `RequestUri`, such as `exam ple.domain`.
    HttpUriError(url::ParseError),
    /// An invalid `HttpVersion`, such as `HTP/1.1`
    HttpVersionError,
    /// An invalid `Header`.
    HttpHeaderError,
    /// An invalid `Status`, such as `1337 ELITE`.
    HttpStatusError,
    /// An `IoError` that occured while trying to read or write to a network stream.
    HttpIoError(IoError),
}

impl Error for HttpError {
    fn description(&self) -> &str {
        match *self {
            HttpMethodError => "Invalid Method specified",
            HttpUriError(_) => "Invalid Request URI specified",
            HttpVersionError => "Invalid HTTP version specified",
            HttpHeaderError => "Invalid Header provided",
            HttpStatusError => "Invalid Status provided",
            HttpIoError(_) => "An IoError occurred while connecting to the specified network",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            HttpIoError(ref error) => Some(error as &Error),
            HttpUriError(ref error) => Some(error as &Error),
            _ => None,
        }
    }
}

impl FromError<IoError> for HttpError {
    fn from_error(err: IoError) -> HttpError {
        HttpIoError(err)
    }
}

impl FromError<url::ParseError> for HttpError {
    fn from_error(err: url::ParseError) -> HttpError {
        HttpUriError(err)
    }
}

//FIXME: when Opt-in Built-in Types becomes a thing, we can force these structs
//to be Send. For now, this has the compiler do a static check.
fn _assert_send<T: Send>() {
    _assert_send::<client::Request<net::Fresh>>();
    _assert_send::<client::Response>();
}
<commit_msg>Typo: wrapped -> wrapper<commit_after>#![feature(macro_rules, phase, default_type_params, slicing_syntax, globs)]
#![deny(missing_docs)]
#![deny(warnings)]
#![experimental]

//! # Hyper
//! Hyper is a fast, modern HTTP implementation written in and for Rust. It
//! is a low-level typesafe abstraction over raw HTTP, providing an elegant
//! layer over "stringly-typed" HTTP.
//!
//! Hyper offers both an HTTP/S client an HTTP server which can be used to drive
//! complex web applications written entirely in Rust.
//!
//! ## Internal Design
//!
//! Hyper is designed as a relatively low-level wrapper over raw HTTP. It should
//! allow the implementation of higher-level abstractions with as little pain as
//! possible, and should not irrevocably hide any information from its users.
//!
//! ### Common Functionality
//!
//! Functionality and code shared between the Server and Client implementations can
//! be found in `src` directly - this includes `NetworkStream`s, `Method`s,
//! `StatusCode`, and so on.
//!
//! #### Methods
//!
//! Methods are represented as a single `enum` to remain as simple as possible.
//! Extension Methods are represented as raw `String`s. A method's safety and
//! idempotence can be accessed using the `safe` and `idempotent` methods.
//!
//! #### StatusCode
//!
//! Status codes are also represented as a single, exhaustive, `enum`. This
//! representation is efficient, typesafe, and ergonomic as it allows the use of
//! `match` to disambiguate known status codes.
//!
//! #### Headers
//!
//! Hyper's header representation is likely the most complex API exposed by Hyper.
//!
//! Hyper's headers are an abstraction over an internal `HashMap` and provides a
//! typesafe API for interacting with headers that does not rely on the use of
//! "string-typing."
//!
//! Each HTTP header in Hyper has an associated type and implementation of the
//! `Header` trait, which defines an HTTP headers name as a string, how to parse
//! that header, and how to format that header.
//!
//! Headers are then parsed from the string representation lazily when the typed
//! representation of a header is requested and formatted back into their string
//! representation when headers are written back to the client.
//!
//! #### NetworkStream and NetworkAcceptor
//!
//! These are found in `src/net.rs` and define the interface that acceptors and
//! streams must fulfill for them to be used within Hyper. They are by and large
//! internal tools and you should only need to mess around with them if you want to
//! mock or replace `TcpStream` and `TcpAcceptor`.
//!
//! ### Server
//!
//! Server-specific functionality, such as `Request` and `Response`
//! representations, are found in in `src/server`.
//!
//! #### Handler + Server
//!
//! A `Handler` in Hyper accepts a `Request` and `Response`. This is where
//! user-code can handle each connection. The server accepts connections in a
//! task pool with a customizable number of threads, and passes the Request /
//! Response to the handler.
//!
//! #### Request
//!
//! An incoming HTTP Request is represented as a struct containing
//! a `Reader` over a `NetworkStream`, which represents the body, headers, a remote
//! address, an HTTP version, and a `Method` - relatively standard stuff.
//!
//! `Request` implements `Reader` itself, meaning that you can ergonomically get
//! the body out of a `Request` using standard `Reader` methods and helpers.
//!
//! #### Response
//!
//! An outgoing HTTP Response is also represented as a struct containing a `Writer`
//! over a `NetworkStream` which represents the Response body in addition to
//! standard items such as the `StatusCode` and HTTP version. `Response`'s `Writer`
//! implementation provides a streaming interface for sending data over to the
//! client.
//!
//! One of the traditional problems with representing outgoing HTTP Responses is
//! tracking the write-status of the Response - have we written the status-line,
//! the headers, the body, etc.? Hyper tracks this information statically using the
//! type system and prevents you, using the type system, from writing headers after
//! you have started writing to the body or vice versa.
//!
//! Hyper does this through a phantom type parameter in the definition of Response,
//! which tracks whether you are allowed to write to the headers or the body. This
//! phantom type can have two values `Fresh` or `Streaming`, with `Fresh`
//! indicating that you can write the headers and `Streaming` indicating that you
//! may write to the body, but not the headers.
//!
//! ### Client
//!
//! Client-specific functionality, such as `Request` and `Response`
//! representations, are found in `src/client`.
//!
//! #### Request
//!
//! An outgoing HTTP Request is represented as a struct containing a `Writer` over
//! a `NetworkStream` which represents the Request body in addition to the standard
//! information such as headers and the request method.
//!
//! Outgoing Requests track their write-status in almost exactly the same way as
//! outgoing HTTP Responses do on the Server, so we will defer to the explanation
//! in the documentation for sever Response.
//!
//! Requests expose an efficient streaming interface instead of a builder pattern,
//! but they also provide the needed interface for creating a builder pattern over
//! the API exposed by core Hyper.
//!
//! #### Response
//!
//! Incoming HTTP Responses are represented as a struct containing a `Reader` over
//! a `NetworkStream` and contain headers, a status, and an http version. They
//! implement `Reader` and can be read to get the data out of a `Response`.
//!

extern crate "rustc-serialize" as serialize;
extern crate time;
extern crate url;
extern crate openssl;
#[phase(plugin,link)] extern crate log;
#[cfg(test)] extern crate test;
extern crate "unsafe-any" as uany;
extern crate cookie;
extern crate mucell;

pub use std::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr, Port};
pub use mimewrapper::mime;
pub use url::Url;
pub use client::Client;
pub use method::Method::{Get, Head, Post, Delete};
pub use status::StatusCode::{Ok, BadRequest, NotFound};
pub use server::Server;

use std::fmt;
use std::error::{Error, FromError};
use std::io::IoError;

use std::rt::backtrace;

use self::HttpError::{HttpMethodError, HttpUriError, HttpVersionError,
                      HttpHeaderError, HttpStatusError, HttpIoError};

macro_rules! todo(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) {
        format_args!(|args| log!(5, "TODO: {}", args), $($arg)*)
    })
);

#[allow(dead_code)]
struct Trace;

impl fmt::Show for Trace {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let _ = backtrace::write(fmt);
        Result::Ok(())
    }
}

macro_rules! trace(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) {
        format_args!(|args| log!(5, "{}\n{}", args, ::Trace), $($arg)*)
    })
);

macro_rules! inspect(
    ($name:expr, $value:expr) => ({
        let v = $value;
        debug!("inspect: {} = {}", $name, v);
        v
    })
);

#[cfg(test)]
#[macro_escape]
mod mock;

pub mod client;
pub mod method;
pub mod header;
pub mod http;
pub mod net;
pub mod server;
pub mod status;
pub mod uri;
pub mod version;

mod mimewrapper {
    /// Re-exporting the mime crate, for convenience.
    extern crate mime;
}

/// Result type often returned from methods that can have `HttpError`s.
pub type HttpResult<T> = Result<T, HttpError>;

/// A set of errors that can occur parsing HTTP streams.
#[deriving(Show, PartialEq, Clone)]
pub enum HttpError {
    /// An invalid `Method`, such as `GE,T`.
    HttpMethodError,
    /// An invalid `RequestUri`, such as `exam ple.domain`.
    HttpUriError(url::ParseError),
    /// An invalid `HttpVersion`, such as `HTP/1.1`
    HttpVersionError,
    /// An invalid `Header`.
    HttpHeaderError,
    /// An invalid `Status`, such as `1337 ELITE`.
    HttpStatusError,
    /// An `IoError` that occured while trying to read or write to a network stream.
    HttpIoError(IoError),
}

impl Error for HttpError {
    fn description(&self) -> &str {
        match *self {
            HttpMethodError => "Invalid Method specified",
            HttpUriError(_) => "Invalid Request URI specified",
            HttpVersionError => "Invalid HTTP version specified",
            HttpHeaderError => "Invalid Header provided",
            HttpStatusError => "Invalid Status provided",
            HttpIoError(_) => "An IoError occurred while connecting to the specified network",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            HttpIoError(ref error) => Some(error as &Error),
            HttpUriError(ref error) => Some(error as &Error),
            _ => None,
        }
    }
}

impl FromError<IoError> for HttpError {
    fn from_error(err: IoError) -> HttpError {
        HttpIoError(err)
    }
}

impl FromError<url::ParseError> for HttpError {
    fn from_error(err: url::ParseError) -> HttpError {
        HttpUriError(err)
    }
}

//FIXME: when Opt-in Built-in Types becomes a thing, we can force these structs
//to be Send. For now, this has the compiler do a static check.
fn _assert_send<T: Send>() {
    _assert_send::<client::Request<net::Fresh>>();
    _assert_send::<client::Response>();
}
<|endoftext|>


<commit_before>extern crate xmltree;
extern crate hyper;
extern crate url;
extern crate regex;

use hyper::Client;
use hyper::header::Connection;
use std::io::Read;
use std::io::Write;
use regex::Regex;

/// Turns "123" into 123
fn intify(instr: &str) -> u32{
    // TODO: Better error handling
    instr.to_owned().parse::<u32>().unwrap()
}

/// Errors in contacting TheTVDB
#[derive(Debug)]
pub enum TvdbError {
    SeriesNotFound,
    CommunicationError{reason: String},
    DataError{reason: String},
    Cancelled,
}

/// Series ID from TheTVDB.com, along with language
#[derive(Debug,Clone)]
pub struct EpisodeId{
    seriesid: u32,
    lang: String,
}

impl EpisodeId{
    pub fn new(seriesid: u32, lang: &str) -> EpisodeId{
        EpisodeId{
            seriesid: seriesid,
            lang: lang.to_owned(),
        }
    }
}

impl From<u32> for EpisodeId{
    fn from(x: u32) -> Self{
        EpisodeId{seriesid: x, lang: "en".to_owned()}
    }
}

impl From<SeriesSearchResult> for EpisodeId{
    fn from(x: SeriesSearchResult) -> Self{
        EpisodeId{seriesid: x.seriesid, lang: x.language}
    }
}

/// Series info as returned from TheTVDB's series search method:
/// http://www.thetvdb.com/wiki/index.php?title=API:GetSeries
#[derive(Debug,Clone)]
pub struct SeriesSearchResult{
    /// TheTVDB's series ID ('seriesid' is preferred over 'id' from XML response)
    pub seriesid: u32,

    /// Series name in the language indicated by `language`
    pub seriesname: String,

    /// Language this episode information is in
    pub language: String,

    /// Description of series
    pub overview: Option<String>,

    /// Relative path to the highest rated banner
    pub banner: Option<String>,

    /// [IMDB](http://www.imdb.com/) ID for this series
    pub imdb_id: Option<String>,

    /// First aired date
    //pub firstaired: Date,

    /// Network this series aired on
    pub network: Option<String>,

    /// [zap2it](http://zap2it.com/) ID for this series
    pub zap2it_id: Option<String>,
}

/// Base episode record,
/// http://www.thetvdb.com/wiki/index.php?title=API:Base_Episode_Record
#[derive(Debug,Clone)]
pub struct EpisodeInfo{
    pub id: u32, //id
    // Combined_episodenumber
    // Combined_season
    // DVD_chapter
    // DVD_discid
    // DVD_episodenumber
    // DVD_season
    // Director
    // EpImgFlag
    pub episodename: String, // EpisodeName
    // EpisodeNumber
    // FirstAired
    // GuestStars
    // IMDB_ID
    // Language
    // Overview
    // ProductionCode
    // Rating
    // RatingCount
    // SeasonNumber
    // Writer
    // absolute_number
    // airsafter_season
    // airsbefore_episode
    // airsbefore_season
    // filename
    // lastupdated
    // seasonid
    // seriesid
    // thumb_added
    // thumb_height
    // thumb_width
}

fn get_xmltree_from_url(url: hyper::Url) -> Result<xmltree::Element, TvdbError>{
    // Check if URL is in cache
    let urlstr = url.serialize();
    let re = Regex::new("[^a-zA-Z0-9_-]+").unwrap();
    let cachefile = format!("cache/cache__{}", re.replace_all(&urlstr, "_"));

    let mut body = Vec::new();

    if std::path::Path::new(&cachefile).exists() {
        println!("Reading from cached path");
        let f = std::fs::File::open(&cachefile).ok().expect("failed to open cache file");
        let mut reader = std::io::BufReader::new(f);
        reader.read_to_end(&mut body).unwrap();
    } else {
        let client = Client::new();
        let res = client.get(url)
            .header(Connection::close())
            .send();

        let mut res = match res {
            Err(e) => return Err(TvdbError::CommunicationError{reason: format!("Error contacting TVDB: {}", e)}), // FIXME: http://stackoverflow.com/questions/28911833/error-handling-best-practices
            Ok(r) => r
        };

        // Read the Response.
        res.read_to_end(&mut body).expect("Failed to read response");
    }

    {
        println!("Saving XML to {}", cachefile);
        std::fs::create_dir_all("cache").expect("Failed to create cache dir");
        let mut f = std::fs::File::create(cachefile).ok().expect("Failed to create file");
        f.write_all(&mut body).ok().unwrap();
    }

    // Parse XML
    let bs = String::from_utf8(body).unwrap();
    let tree = xmltree::Element::parse(bs.as_bytes());

    return Ok(tree);
}

/// Main interface
#[derive(Debug,Clone)]
pub struct Tvdb{
    key: String,
}

impl Tvdb{
    /// Initalise API with the given API key. A key can be aquired via
    /// the [API Key Registration page](http://thetvdb.com/?tab=apiregister)
    pub fn new(key: String) -> Tvdb{
        Tvdb{key: key}
    }

    /// Searches for a given series name.
    pub fn search(&self, seriesname: String, lang: String) -> Result<Vec<SeriesSearchResult>, TvdbError>{
        let params = url::form_urlencoded::serialize([("seriesname", &seriesname), ("language", &lang)].iter());
        let formatted_url = format!("http://thetvdb.com/api/GetSeries.php?{}", params);
        let url = hyper::Url::parse(&formatted_url).ok().expect("invalid URL");
        println!("Getting {}", url);

        let tree = try!(get_xmltree_from_url(url));

        // Convert XML into structs
        let mut results : Vec<SeriesSearchResult> = vec![];

        for child in tree.children.iter(){

            fn get_text(child: &xmltree::Element, x: &str) -> Option<String>{
                child.get_child(x).and_then(|id_child| id_child.text.clone())
            }

            let r = SeriesSearchResult{
                seriesid:   intify(&get_text(child, "seriesid").expect("Search result XML missing 'seriesid' element")),
                seriesname: get_text(child, "SeriesName").expect("Search result XML Missing 'SeriesName' element"),
                language:   get_text(child, "language").expect("Search result XML missing 'language' element"),
                overview:   get_text(child, "Overview"),
                banner:     get_text(child, "banner"),
                imdb_id:    get_text(child, "IMDB_ID"),
                //firstaired: Date,
                network:    get_text(child, "Network"),
                zap2it_id:  get_text(child, "zap2it_id"),
            };

            results.push(r);
        }

        if results.is_empty(){
            return Err(TvdbError::SeriesNotFound);
        }

        return Ok(results);
    }

    fn episode_inner(&self, epid: EpisodeId, season: u32, episode: u32) -> Result<EpisodeInfo, TvdbError>{
        // <mirrorpath>/api/<apikey>/series/{seriesid}/default/{season}/{episode}/{language}.xml

        let formatted_url = format!("http://thetvdb.com/api/{apikey}/series/{seriesid}/default/{season}/{episode}/{language}.xml",
                                    apikey=self.key,
                                    seriesid=epid.seriesid,
                                    language=epid.lang,
                                    season=season,
                                    episode=episode,
                                    );
        let url = hyper::Url::parse(&formatted_url).ok().expect("invalid URL");
        println!("Getting {}", url);

        // Perform request
        let tree = try!(get_xmltree_from_url(url));
        let root = tree.children.first().unwrap();

        fn get_text(child: &xmltree::Element, x: &str) -> Option<String>{
            child.get_child(x).and_then(|id_child| id_child.text.clone())
        }

        // Convert XML into struct
        Ok(EpisodeInfo{
            id: intify(&get_text(root, "id").unwrap()),
            episodename: get_text(root, "EpisodeName").unwrap(),
        })
    }

    /// Get episode information for given season/episode number
    pub fn episode<T: Into<EpisodeId>>(&self, epid: T, season: u32, episode: u32) -> Result<EpisodeInfo, TvdbError>{
        self.episode_inner(epid.into(), season, episode)
    }
}

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

    const APIKEY: &'static str = "0629B785CE550C8D";

    #[test]
    fn search() {
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned());
        assert!(sr.ok().unwrap()[0].seriesname == "Scrubs");
    }

    #[test]
    fn nonexist() {
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("ladlkgdklfgsdfglk".to_owned(), "en".to_owned());
        assert!(sr.is_err());
    }

    #[test]
    fn lookup_by_epid(){
        let api = Tvdb::new(APIKEY.to_owned());
        let ep = api.episode(EpisodeId::new(76156, "en"), 1, 2).ok().unwrap();
        assert!(ep.episodename == "My Mentor");
    }

    #[test]
    fn lookup_by_u32(){
        let api = Tvdb::new(APIKEY.to_owned());
        let ep = api.episode(76156, 1, 2).ok().unwrap();
        assert!(ep.episodename == "My Mentor");
    }

    #[test]
    fn epinfo_default(){
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned()).ok().unwrap();
        let ep = api.episode(sr[0].clone(), 1, 2).ok().unwrap();
        assert!(ep.episodename == "My Mentor");
    }

}
<commit_msg>Make Tvdb.key public<commit_after>extern crate xmltree;
extern crate hyper;
extern crate url;
extern crate regex;

use hyper::Client;
use hyper::header::Connection;
use std::io::Read;
use std::io::Write;
use regex::Regex;

/// Turns "123" into 123
fn intify(instr: &str) -> u32{
    // TODO: Better error handling
    instr.to_owned().parse::<u32>().unwrap()
}

/// Errors in contacting TheTVDB
#[derive(Debug)]
pub enum TvdbError {
    SeriesNotFound,
    CommunicationError{reason: String},
    DataError{reason: String},
    Cancelled,
}

/// Series ID from TheTVDB.com, along with language
#[derive(Debug,Clone)]
pub struct EpisodeId{
    seriesid: u32,
    lang: String,
}

impl EpisodeId{
    pub fn new(seriesid: u32, lang: &str) -> EpisodeId{
        EpisodeId{
            seriesid: seriesid,
            lang: lang.to_owned(),
        }
    }
}

impl From<u32> for EpisodeId{
    fn from(x: u32) -> Self{
        EpisodeId{seriesid: x, lang: "en".to_owned()}
    }
}

impl From<SeriesSearchResult> for EpisodeId{
    fn from(x: SeriesSearchResult) -> Self{
        EpisodeId{seriesid: x.seriesid, lang: x.language}
    }
}

/// Series info as returned from TheTVDB's series search method:
/// http://www.thetvdb.com/wiki/index.php?title=API:GetSeries
#[derive(Debug,Clone)]
pub struct SeriesSearchResult{
    /// TheTVDB's series ID ('seriesid' is preferred over 'id' from XML response)
    pub seriesid: u32,

    /// Series name in the language indicated by `language`
    pub seriesname: String,

    /// Language this episode information is in
    pub language: String,

    /// Description of series
    pub overview: Option<String>,

    /// Relative path to the highest rated banner
    pub banner: Option<String>,

    /// [IMDB](http://www.imdb.com/) ID for this series
    pub imdb_id: Option<String>,

    /// First aired date
    //pub firstaired: Date,

    /// Network this series aired on
    pub network: Option<String>,

    /// [zap2it](http://zap2it.com/) ID for this series
    pub zap2it_id: Option<String>,
}

/// Base episode record,
/// http://www.thetvdb.com/wiki/index.php?title=API:Base_Episode_Record
#[derive(Debug,Clone)]
pub struct EpisodeInfo{
    pub id: u32, //id
    // Combined_episodenumber
    // Combined_season
    // DVD_chapter
    // DVD_discid
    // DVD_episodenumber
    // DVD_season
    // Director
    // EpImgFlag
    pub episodename: String, // EpisodeName
    // EpisodeNumber
    // FirstAired
    // GuestStars
    // IMDB_ID
    // Language
    // Overview
    // ProductionCode
    // Rating
    // RatingCount
    // SeasonNumber
    // Writer
    // absolute_number
    // airsafter_season
    // airsbefore_episode
    // airsbefore_season
    // filename
    // lastupdated
    // seasonid
    // seriesid
    // thumb_added
    // thumb_height
    // thumb_width
}

fn get_xmltree_from_url(url: hyper::Url) -> Result<xmltree::Element, TvdbError>{
    // Check if URL is in cache
    let urlstr = url.serialize();
    let re = Regex::new("[^a-zA-Z0-9_-]+").unwrap();
    let cachefile = format!("cache/cache__{}", re.replace_all(&urlstr, "_"));

    let mut body = Vec::new();

    if std::path::Path::new(&cachefile).exists() {
        println!("Reading from cached path");
        let f = std::fs::File::open(&cachefile).ok().expect("failed to open cache file");
        let mut reader = std::io::BufReader::new(f);
        reader.read_to_end(&mut body).unwrap();
    } else {
        let client = Client::new();
        let res = client.get(url)
            .header(Connection::close())
            .send();

        let mut res = match res {
            Err(e) => return Err(TvdbError::CommunicationError{reason: format!("Error contacting TVDB: {}", e)}), // FIXME: http://stackoverflow.com/questions/28911833/error-handling-best-practices
            Ok(r) => r
        };

        // Read the Response.
        res.read_to_end(&mut body).expect("Failed to read response");
    }

    {
        println!("Saving XML to {}", cachefile);
        std::fs::create_dir_all("cache").expect("Failed to create cache dir");
        let mut f = std::fs::File::create(cachefile).ok().expect("Failed to create file");
        f.write_all(&mut body).ok().unwrap();
    }

    // Parse XML
    let bs = String::from_utf8(body).unwrap();
    let tree = xmltree::Element::parse(bs.as_bytes());

    return Ok(tree);
}

/// Main interface
#[derive(Debug,Clone)]
pub struct Tvdb{
    pub key: String,
}

impl Tvdb{
    /// Initalise API with the given API key. A key can be aquired via
    /// the [API Key Registration page](http://thetvdb.com/?tab=apiregister)
    pub fn new(key: String) -> Tvdb{
        Tvdb{key: key}
    }

    /// Searches for a given series name.
    pub fn search(&self, seriesname: String, lang: String) -> Result<Vec<SeriesSearchResult>, TvdbError>{
        let params = url::form_urlencoded::serialize([("seriesname", &seriesname), ("language", &lang)].iter());
        let formatted_url = format!("http://thetvdb.com/api/GetSeries.php?{}", params);
        let url = hyper::Url::parse(&formatted_url).ok().expect("invalid URL");
        println!("Getting {}", url);

        let tree = try!(get_xmltree_from_url(url));

        // Convert XML into structs
        let mut results : Vec<SeriesSearchResult> = vec![];

        for child in tree.children.iter(){

            fn get_text(child: &xmltree::Element, x: &str) -> Option<String>{
                child.get_child(x).and_then(|id_child| id_child.text.clone())
            }

            let r = SeriesSearchResult{
                seriesid:   intify(&get_text(child, "seriesid").expect("Search result XML missing 'seriesid' element")),
                seriesname: get_text(child, "SeriesName").expect("Search result XML Missing 'SeriesName' element"),
                language:   get_text(child, "language").expect("Search result XML missing 'language' element"),
                overview:   get_text(child, "Overview"),
                banner:     get_text(child, "banner"),
                imdb_id:    get_text(child, "IMDB_ID"),
                //firstaired: Date,
                network:    get_text(child, "Network"),
                zap2it_id:  get_text(child, "zap2it_id"),
            };

            results.push(r);
        }

        if results.is_empty(){
            return Err(TvdbError::SeriesNotFound);
        }

        return Ok(results);
    }

    fn episode_inner(&self, epid: EpisodeId, season: u32, episode: u32) -> Result<EpisodeInfo, TvdbError>{
        // <mirrorpath>/api/<apikey>/series/{seriesid}/default/{season}/{episode}/{language}.xml

        let formatted_url = format!("http://thetvdb.com/api/{apikey}/series/{seriesid}/default/{season}/{episode}/{language}.xml",
                                    apikey=self.key,
                                    seriesid=epid.seriesid,
                                    language=epid.lang,
                                    season=season,
                                    episode=episode,
                                    );
        let url = hyper::Url::parse(&formatted_url).ok().expect("invalid URL");
        println!("Getting {}", url);

        // Perform request
        let tree = try!(get_xmltree_from_url(url));
        let root = tree.children.first().unwrap();

        fn get_text(child: &xmltree::Element, x: &str) -> Option<String>{
            child.get_child(x).and_then(|id_child| id_child.text.clone())
        }

        // Convert XML into struct
        Ok(EpisodeInfo{
            id: intify(&get_text(root, "id").unwrap()),
            episodename: get_text(root, "EpisodeName").unwrap(),
        })
    }

    /// Get episode information for given season/episode number
    pub fn episode<T: Into<EpisodeId>>(&self, epid: T, season: u32, episode: u32) -> Result<EpisodeInfo, TvdbError>{
        self.episode_inner(epid.into(), season, episode)
    }
}

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

    const APIKEY: &'static str = "0629B785CE550C8D";

    #[test]
    fn search() {
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned());
        assert!(sr.ok().unwrap()[0].seriesname == "Scrubs");
    }

    #[test]
    fn nonexist() {
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("ladlkgdklfgsdfglk".to_owned(), "en".to_owned());
        assert!(sr.is_err());
    }

    #[test]
    fn lookup_by_epid(){
        let api = Tvdb::new(APIKEY.to_owned());
        let ep = api.episode(EpisodeId::new(76156, "en"), 1, 2).ok().unwrap();
        assert!(ep.episodename == "My Mentor");
    }

    #[test]
    fn lookup_by_u32(){
        let api = Tvdb::new(APIKEY.to_owned());
        let ep = api.episode(76156, 1, 2).ok().unwrap();
        assert!(ep.episodename == "My Mentor");
    }

    #[test]
    fn epinfo_default(){
        let api = Tvdb::new(APIKEY.to_owned());
        let sr = api.search("scrubs".to_owned(), "en".to_owned()).ok().unwrap();
        let ep = api.episode(sr[0].clone(), 1, 2).ok().unwrap();
        assert!(ep.episodename == "My Mentor");
    }

}
<|endoftext|>


<commit_before>//! FizzBuzz helper library for Rust and Cargo
//!
//! Instructions: Add to your cargo tomato and go!
//!
//! # Example
//!
//! ```
//! use fx::Fx;
//!
//! let sum_of_non_fizz_buzz_values = (1..101)
//!     .map(fx::default)
//!     .fold(0, |a,b| a + if let Fx::I(n) = b {
//!         n
//!     } else {
//!         0
//!     });
//!
//! assert!(sum_of_non_fizz_buzz_values == 2632);
//! ```

/// Enum representing value status.
pub enum Fx {
    Fizz,
    Buzz,
    FizzBuzz,
    I(u32),
}

impl Fx {
    /// Create new Fx enum using standard FizzBuzz rules.
    pub fn new(n: u32) -> Fx {
        Fx::arbitrary(n, |n| n % 3 == 0, |n| n % 5 == 0)
    }

    /// Create new Fx enum using arbitrary FizzBuzz rules.
    pub fn arbitrary<FA, FB>(n: u32, fa: FA, fb: FB) -> Fx
        where FA: Fn(u32) -> bool,
              FB: Fn(u32) -> bool
    {
        match (n, fa(n), fb(n)) {
            (_, true, true) => Fx::FizzBuzz,
            (_, true, _) => Fx::Fizz,
            (_, _, true) => Fx::Buzz,
            (n, _, _) => Fx::I(n),
        }
    }
}

/// Print Fx value to console; no need to futz with formatting.
/// on the client side.
impl std::fmt::Display for Fx {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            &Fx::FizzBuzz => write!(f, "FizzBuzz"),
            &Fx::Fizz => write!(f, "Fizz"),
            &Fx::Buzz => write!(f, "Buzz"),
            &Fx::I(n) => write!(f, "{}", n),
        }
    }
}

/// Convenience method for creating a new default Fx enum.
pub fn default(n: u32) -> Fx {
    Fx::new(n)
}

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

    #[test]
    fn integers_work() {
        assert!(format!("{}", Fx::new(2)) == "2");
    }

    #[test]
    fn fizz_works() {
        assert!(format!("{}", Fx::new(3)) == "Fizz");
    }

    #[test]
    fn buzz_works() {
        assert!(format!("{}", Fx::new(5)) == "Buzz");
    }

    #[test]
    fn fizz_buzz_works() {
        assert!(format!("{}", Fx::new(15)) == "FizzBuzz");
    }
}
<commit_msg>Added standard fizzbuzz example<commit_after>//! FizzBuzz helper library for Rust and Cargo
//!
//! Instructions: Add to your cargo tomato and go!
//!
//! # Example 1: Basic fizzbuzz
//!
//! ```
//! use fx::Fx;
//!
//! for i in (1..101).map(fx::default) {
//!     println!("{}", i);
//! }
//! ```
//!
//! # Example 2: Sum of inverse
//!
//! ```
//! use fx::Fx;
//!
//! let sum_of_non_fizz_buzz_values = (1..101)
//!     .map(fx::default)
//!     .fold(0, |a,b| a + if let Fx::I(n) = b {
//!         n
//!     } else {
//!         0
//!     });
//!
//! assert!(sum_of_non_fizz_buzz_values == 2632);
//! ```

/// Enum representing value status.
pub enum Fx {
    Fizz,
    Buzz,
    FizzBuzz,
    I(u32),
}

impl Fx {
    /// Create new Fx enum using standard FizzBuzz rules.
    pub fn new(n: u32) -> Fx {
        Fx::arbitrary(n, |n| n % 3 == 0, |n| n % 5 == 0)
    }

    /// Create new Fx enum using arbitrary FizzBuzz rules.
    pub fn arbitrary<FA, FB>(n: u32, fa: FA, fb: FB) -> Fx
        where FA: Fn(u32) -> bool,
              FB: Fn(u32) -> bool
    {
        match (n, fa(n), fb(n)) {
            (_, true, true) => Fx::FizzBuzz,
            (_, true, _) => Fx::Fizz,
            (_, _, true) => Fx::Buzz,
            (n, _, _) => Fx::I(n),
        }
    }
}

/// Print Fx value to console; no need to futz with formatting.
/// on the client side.
impl std::fmt::Display for Fx {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            &Fx::FizzBuzz => write!(f, "FizzBuzz"),
            &Fx::Fizz => write!(f, "Fizz"),
            &Fx::Buzz => write!(f, "Buzz"),
            &Fx::I(n) => write!(f, "{}", n),
        }
    }
}

/// Convenience method for creating a new default Fx enum.
pub fn default(n: u32) -> Fx {
    Fx::new(n)
}

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

    #[test]
    fn integers_work() {
        assert!(format!("{}", Fx::new(2)) == "2");
    }

    #[test]
    fn fizz_works() {
        assert!(format!("{}", Fx::new(3)) == "Fizz");
    }

    #[test]
    fn buzz_works() {
        assert!(format!("{}", Fx::new(5)) == "Buzz");
    }

    #[test]
    fn fizz_buzz_works() {
        assert!(format!("{}", Fx::new(15)) == "FizzBuzz");
    }
}
<|endoftext|>