<commit_before>//! Core I/O traits and combinators when working with Tokio.
//!
//! A description of the high-level I/O combinators can be [found online] in
//! addition to a description of the [low level details].
//!
//! [found online]: https://tokio.rs/docs/getting-started/core/
//! [low level details]: https://tokio.rs/docs/going-deeper/core-low-level/

#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-io/0.1")]

#[macro_use]
extern crate log;

#[macro_use]
extern crate futures;
extern crate bytes;

use std::io as std_io;
use std::io::Write;

use futures::{Async, Poll};
use futures::future::BoxFuture;
use futures::stream::BoxStream;

use bytes::{Buf, BufMut};

/// A convenience typedef around a `Future` whose error component is `io::Error`
pub type IoFuture<T> = BoxFuture<T, std_io::Error>;

/// A convenience typedef around a `Stream` whose error component is `io::Error`
pub type IoStream<T> = BoxStream<T, std_io::Error>;

/// A convenience macro for working with `io::Result<T>` from the `Read` and
/// `Write` traits.
///
/// This macro takes `io::Result<T>` as input, and returns `T` as the output. If
/// the input type is of the `Err` variant, then `Poll::NotReady` is returned if
/// it indicates `WouldBlock` or otherwise `Err` is returned.
#[macro_export]
macro_rules! try_nb {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => {
            return Ok(::futures::Async::NotReady)
        }
        Err(e) => return Err(e.into()),
    })
}

pub mod io;
pub mod codec;

mod copy;
mod flush;
mod framed;
mod framed_read;
mod framed_write;
mod length_delimited;
mod lines;
mod read;
mod read_exact;
mod read_to_end;
mod read_until;
mod shutdown;
mod split;
mod window;
mod write_all;

use codec::{Decoder, Encoder, Framed};
use split::{ReadHalf, WriteHalf};

/// A trait for readable objects which operated in an asynchronous and
/// futures-aware fashion.
///
/// This trait inherits from `io::Read` and indicates as a marker that an I/O
/// object is **nonblocking**, meaning that it will return an error instead of
/// blocking when bytes are read. Specifically this means that the `read`
/// function for traits that implement this type can have a few return values:
///
/// * `Ok(n)` means that `n` bytes of data was immediately read and placed into
///   the output buffer, where `n` == 0 implies that EOF has been reached.
/// * `Err(e) if e.kind() == ErrorKind::WouldBlock` means that no data was read
///   into the buffer provided. The I/O object is not currently readable but may
///   become readable in the future. Most importantly, **the current future's
///   task is scheduled to get unparked when the object is readable**. This
///   means that like `Future::poll` you'll receive a notification when the I/O
///   object is readable again.
/// * `Err(e)` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncRead: std_io::Read {
    /// Prepares an uninitialized buffer to be safe to pass to `read`. Returns
    /// `true` if the supplied buffer was zeroed out.
    ///
    /// While it would be highly unusual, implementations of [`io::Read`] are
    /// able to read data from the buffer passed as an argument. Because of
    /// this, the buffer passed to [`io::Read`] must be initialized memory. In
    /// situations where large numbers of buffers are used, constantly having to
    /// zero out buffers can be expensive.
    ///
    /// This function does any necessary work to prepare an uninitialized buffer
    /// to be safe to pass to `read`. If `read` guarantees to never attempt read
    /// data out of the supplied buffer, then `prepare_uninitialized_buffer`
    /// doesn't need to do any work.
    ///
    /// If this function returns `true`, then the memory has been zeroed out.
    /// This allows implementations of `AsyncRead` which are composed of
    /// multiple sub implementations to efficiently implement
    /// `prepare_uninitialized_buffer`.
    ///
    /// This function isn't actually `unsafe` to call but `unsafe` to implement.
    /// The implementor must ensure that either the whole `buf` has been zeroed
    /// or `read_buf()` overwrites the buffer without reading it and returns
    /// correct value.
    ///
    /// This function is called from [`read_buf`].
    ///
    /// [`io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
    /// [`read_buf`]: #method.read_buf
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        for i in 0..buf.len() {
            buf[i] = 0;
        }

        true
    }

    /// Pull some bytes from this source into the specified `Buf`, returning
    /// how many bytes were read.
    ///
    /// The `buf` provided will have bytes read into it and the internal cursor
    /// will be advanced if any bytes were read. Note that this method typically
    /// will not reallocate the buffer provided.
    fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
        where Self: Sized,
    {
        if !buf.has_remaining_mut() {
            return Ok(Async::Ready(0));
        }

        unsafe {
            let n = {
                let b = buf.bytes_mut();

                self.prepare_uninitialized_buffer(b);

                try_nb!(self.read(b))
            };

            buf.advance_mut(n);
            Ok(Async::Ready(n))
        }
    }

    /// Provides a `Stream` and `Sink` interface for reading and writing to this
    /// `Io` object, using `Decode` and `Encode` to read and write the raw data.
    ///
    /// Raw I/O objects work with byte sequences, but higher-level code usually
    /// wants to batch these into meaningful chunks, called "frames". This
    /// method layers framing on top of an I/O object, by using the `Codec`
    /// traits to handle encoding and decoding of messages frames. Note that
    /// the incoming and outgoing frame types may be distinct.
    ///
    /// This function returns a *single* object that is both `Stream` and
    /// `Sink`; grouping this into a single object is often useful for layering
    /// things like gzip or TLS, which require both read and write access to the
    /// underlying object.
    ///
    /// If you want to work more directly with the streams and sink, consider
    /// calling `split` on the `Framed` returned by this method, which will
    /// break them into separate objects, allowing them to interact more easily.
    fn framed<T: Encoder + Decoder>(self, codec: T) -> Framed<Self, T>
        where Self: AsyncWrite + Sized,
    {
        framed::framed(self, codec)
    }

    /// Helper method for splitting this read/write object into two halves.
    ///
    /// The two halves returned implement the `Read` and `Write` traits,
    /// respectively.
    fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
        where Self: AsyncWrite + Sized,
    {
        split::split(self)
    }
}

impl<T: ?Sized + AsyncRead> AsyncRead for Box<T> {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        (**self).prepare_uninitialized_buffer(buf)
    }
}

impl<'a, T: ?Sized + AsyncRead> AsyncRead for &'a mut T {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        (**self).prepare_uninitialized_buffer(buf)
    }
}

impl<'a> AsyncRead for &'a [u8] {
    unsafe fn prepare_uninitialized_buffer(&self, _buf: &mut [u8]) -> bool {
        false
    }
}

/// A trait for writable objects which operated in an asynchronous and
/// futures-aware fashion.
///
/// This trait inherits from `io::Write` and indicates that an I/O object is
/// **nonblocking**, meaning that it will return an error instead of blocking
/// when bytes are written. Specifically this means that the `write` function
/// for traits that implement this type can have a few return values:
///
/// * `Ok(n)` means that `n` bytes of data was immediately written .
/// * `Err(e) if e.kind() == ErrorKind::WouldBlock` means that no data was
///   written from the buffer provided. The I/O object is not currently
///   writable but may become writable in the future. Most importantly, **the
///   current future's task is scheduled to get unparked when the object is
///   readable**. This means that like `Future::poll` you'll receive a
///   notification when the I/O object is writable again.
/// * `Err(e)` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `write` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncWrite: std_io::Write {
    /// Initiates or attempts to shut down this writer, returning success when
    /// the I/O connection has completely shut down.
    ///
    /// This method is intended to be used for asynchronous shutdown of I/O
    /// connections. For example this is suitable for implementing shutdown of a
    /// TLS connection or calling `TcpStream::shutdown` on a proxied connection.
    ///
    /// This `shutdown` method is required by implementors of the
    /// `AsyncWrite` trait. Wrappers typically just want to proxy this call
    /// through to the wrapped type, and base types will typically implement
    /// shutdown logic here or just return `Ok(().into())`.
    ///
    /// Invocation of a `shutdown` implies invocation of `flush`. Once this
    /// method returns `Ready` it implies that a flush successfully happened
    /// before the shutdown happened.
    ///
    /// # Return value
    ///
    /// This function returns a `Poll<(), io::Error>` classified as such:
    ///
    /// * `Ok(Async::Ready(()))` - indicates that the connection was
    ///   successfully shut down and is now safe to deallocate/drop/close
    ///   resources associated with it. This method means that the current task
    ///   will no longer receive any notifications due to this method and the
    ///   I/O object itself is likely no longer usable.
    ///
    /// * `Ok(Async::NotReady)` - indicates that shutdown is initiated but could
    ///   not complete just yet. This may mean that more I/O needs to happen to
    ///   continue this shutdown operation. The current task is scheduled to
    ///   receive a notification when it's otherwise ready to continue the
    ///   shutdown operation. When woken up this method should be called again.
    ///
    /// * `Err(e)` - indicates a fatal error has happened with shutdown,
    ///   indicating that the shutdown operation did not complete successfully.
    ///   This typically means that the I/O object is no longer usable.
    ///
    /// # Errors
    ///
    /// This function can return normal I/O errors through `Err`, described
    /// above. Additionally this method may also render the underlying
    /// `Write::write` method no longer usable (e.g. will return errors in the
    /// future). It's recommended that once `shutdown` is called the
    /// `write` method is no longer called.
    ///
    /// # Panics
    ///
    /// This function will panic if not called within the context of a future's
    /// task.
    fn shutdown(&mut self) -> Poll<(), std_io::Error>;

    /// Write a `Buf` into this value, returning how many bytes were written.
    ///
    /// Note that this method will advance the `buf` provided automatically by
    /// the number of bytes written.
    fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
        where Self: Sized,
    {
        if !buf.has_remaining() {
            return Ok(Async::Ready(0));
        }

        let n = try_nb!(self.write(buf.bytes()));
        buf.advance(n);
        Ok(Async::Ready(n))
    }
}

impl<T: ?Sized + AsyncWrite> AsyncWrite for Box<T> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        (**self).shutdown()
    }
}
impl<'a, T: ?Sized + AsyncWrite> AsyncWrite for &'a mut T {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        (**self).shutdown()
    }
}

impl AsyncRead for std_io::Repeat {
    unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
        false
    }
}

impl AsyncWrite for std_io::Sink {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

// TODO: Implement `prepare_uninitialized_buffer` for `io::Take`.
// This is blocked on rust-lang/rust#27269
impl<T: AsyncRead> AsyncRead for std_io::Take<T> {
}

// TODO: Implement `prepare_uninitialized_buffer` when upstream exposes inner
// parts
impl<T, U> AsyncRead for std_io::Chain<T, U>
    where T: AsyncRead,
          U: AsyncRead,
{
}

impl<T: AsyncWrite> AsyncWrite for std_io::BufWriter<T> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        try_nb!(self.flush());
        self.get_mut().shutdown()
    }
}

impl<T: AsyncRead> AsyncRead for std_io::BufReader<T> {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        self.get_ref().prepare_uninitialized_buffer(buf)
    }
}

impl<T: AsRef<[u8]>> AsyncRead for std_io::Cursor<T> {
}

impl<'a> AsyncWrite for std_io::Cursor<&'a mut [u8]> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

impl AsyncWrite for std_io::Cursor<Vec<u8>> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

impl AsyncWrite for std_io::Cursor<Box<[u8]>> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

fn _assert_objects() {
    fn _assert<T>() {}
    _assert::<Box<AsyncRead>>();
    _assert::<Box<AsyncWrite>>();
}
<commit_msg>Touch up docs on AsyncWrite::shutdown<commit_after>//! Core I/O traits and combinators when working with Tokio.
//!
//! A description of the high-level I/O combinators can be [found online] in
//! addition to a description of the [low level details].
//!
//! [found online]: https://tokio.rs/docs/getting-started/core/
//! [low level details]: https://tokio.rs/docs/going-deeper/core-low-level/

#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-io/0.1")]

#[macro_use]
extern crate log;

#[macro_use]
extern crate futures;
extern crate bytes;

use std::io as std_io;
use std::io::Write;

use futures::{Async, Poll};
use futures::future::BoxFuture;
use futures::stream::BoxStream;

use bytes::{Buf, BufMut};

/// A convenience typedef around a `Future` whose error component is `io::Error`
pub type IoFuture<T> = BoxFuture<T, std_io::Error>;

/// A convenience typedef around a `Stream` whose error component is `io::Error`
pub type IoStream<T> = BoxStream<T, std_io::Error>;

/// A convenience macro for working with `io::Result<T>` from the `Read` and
/// `Write` traits.
///
/// This macro takes `io::Result<T>` as input, and returns `T` as the output. If
/// the input type is of the `Err` variant, then `Poll::NotReady` is returned if
/// it indicates `WouldBlock` or otherwise `Err` is returned.
#[macro_export]
macro_rules! try_nb {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => {
            return Ok(::futures::Async::NotReady)
        }
        Err(e) => return Err(e.into()),
    })
}

pub mod io;
pub mod codec;

mod copy;
mod flush;
mod framed;
mod framed_read;
mod framed_write;
mod length_delimited;
mod lines;
mod read;
mod read_exact;
mod read_to_end;
mod read_until;
mod shutdown;
mod split;
mod window;
mod write_all;

use codec::{Decoder, Encoder, Framed};
use split::{ReadHalf, WriteHalf};

/// A trait for readable objects which operated in an asynchronous and
/// futures-aware fashion.
///
/// This trait inherits from `io::Read` and indicates as a marker that an I/O
/// object is **nonblocking**, meaning that it will return an error instead of
/// blocking when bytes are read. Specifically this means that the `read`
/// function for traits that implement this type can have a few return values:
///
/// * `Ok(n)` means that `n` bytes of data was immediately read and placed into
///   the output buffer, where `n` == 0 implies that EOF has been reached.
/// * `Err(e) if e.kind() == ErrorKind::WouldBlock` means that no data was read
///   into the buffer provided. The I/O object is not currently readable but may
///   become readable in the future. Most importantly, **the current future's
///   task is scheduled to get unparked when the object is readable**. This
///   means that like `Future::poll` you'll receive a notification when the I/O
///   object is readable again.
/// * `Err(e)` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncRead: std_io::Read {
    /// Prepares an uninitialized buffer to be safe to pass to `read`. Returns
    /// `true` if the supplied buffer was zeroed out.
    ///
    /// While it would be highly unusual, implementations of [`io::Read`] are
    /// able to read data from the buffer passed as an argument. Because of
    /// this, the buffer passed to [`io::Read`] must be initialized memory. In
    /// situations where large numbers of buffers are used, constantly having to
    /// zero out buffers can be expensive.
    ///
    /// This function does any necessary work to prepare an uninitialized buffer
    /// to be safe to pass to `read`. If `read` guarantees to never attempt read
    /// data out of the supplied buffer, then `prepare_uninitialized_buffer`
    /// doesn't need to do any work.
    ///
    /// If this function returns `true`, then the memory has been zeroed out.
    /// This allows implementations of `AsyncRead` which are composed of
    /// multiple sub implementations to efficiently implement
    /// `prepare_uninitialized_buffer`.
    ///
    /// This function isn't actually `unsafe` to call but `unsafe` to implement.
    /// The implementor must ensure that either the whole `buf` has been zeroed
    /// or `read_buf()` overwrites the buffer without reading it and returns
    /// correct value.
    ///
    /// This function is called from [`read_buf`].
    ///
    /// [`io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
    /// [`read_buf`]: #method.read_buf
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        for i in 0..buf.len() {
            buf[i] = 0;
        }

        true
    }

    /// Pull some bytes from this source into the specified `Buf`, returning
    /// how many bytes were read.
    ///
    /// The `buf` provided will have bytes read into it and the internal cursor
    /// will be advanced if any bytes were read. Note that this method typically
    /// will not reallocate the buffer provided.
    fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
        where Self: Sized,
    {
        if !buf.has_remaining_mut() {
            return Ok(Async::Ready(0));
        }

        unsafe {
            let n = {
                let b = buf.bytes_mut();

                self.prepare_uninitialized_buffer(b);

                try_nb!(self.read(b))
            };

            buf.advance_mut(n);
            Ok(Async::Ready(n))
        }
    }

    /// Provides a `Stream` and `Sink` interface for reading and writing to this
    /// `Io` object, using `Decode` and `Encode` to read and write the raw data.
    ///
    /// Raw I/O objects work with byte sequences, but higher-level code usually
    /// wants to batch these into meaningful chunks, called "frames". This
    /// method layers framing on top of an I/O object, by using the `Codec`
    /// traits to handle encoding and decoding of messages frames. Note that
    /// the incoming and outgoing frame types may be distinct.
    ///
    /// This function returns a *single* object that is both `Stream` and
    /// `Sink`; grouping this into a single object is often useful for layering
    /// things like gzip or TLS, which require both read and write access to the
    /// underlying object.
    ///
    /// If you want to work more directly with the streams and sink, consider
    /// calling `split` on the `Framed` returned by this method, which will
    /// break them into separate objects, allowing them to interact more easily.
    fn framed<T: Encoder + Decoder>(self, codec: T) -> Framed<Self, T>
        where Self: AsyncWrite + Sized,
    {
        framed::framed(self, codec)
    }

    /// Helper method for splitting this read/write object into two halves.
    ///
    /// The two halves returned implement the `Read` and `Write` traits,
    /// respectively.
    fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
        where Self: AsyncWrite + Sized,
    {
        split::split(self)
    }
}

impl<T: ?Sized + AsyncRead> AsyncRead for Box<T> {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        (**self).prepare_uninitialized_buffer(buf)
    }
}

impl<'a, T: ?Sized + AsyncRead> AsyncRead for &'a mut T {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        (**self).prepare_uninitialized_buffer(buf)
    }
}

impl<'a> AsyncRead for &'a [u8] {
    unsafe fn prepare_uninitialized_buffer(&self, _buf: &mut [u8]) -> bool {
        false
    }
}

/// A trait for writable objects which operated in an asynchronous and
/// futures-aware fashion.
///
/// This trait inherits from `io::Write` and indicates that an I/O object is
/// **nonblocking**, meaning that it will return an error instead of blocking
/// when bytes are written. Specifically this means that the `write` function
/// for traits that implement this type can have a few return values:
///
/// * `Ok(n)` means that `n` bytes of data was immediately written .
/// * `Err(e) if e.kind() == ErrorKind::WouldBlock` means that no data was
///   written from the buffer provided. The I/O object is not currently
///   writable but may become writable in the future. Most importantly, **the
///   current future's task is scheduled to get unparked when the object is
///   readable**. This means that like `Future::poll` you'll receive a
///   notification when the I/O object is writable again.
/// * `Err(e)` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `write` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncWrite: std_io::Write {
    /// Initiates or attempts to shut down this writer, returning success when
    /// the I/O connection has completely shut down.
    ///
    /// This method is intended to be used for asynchronous shutdown of I/O
    /// connections. For example this is suitable for implementing shutdown of a
    /// TLS connection or calling `TcpStream::shutdown` on a proxied connection.
    /// Protocols sometimes need to flush out final pieces of data or otherwise
    /// perform a graceful shutdown handshake, reading/writing more data as
    /// appropriate. This method is the hook for such protocols to implement the
    /// graceful shutdown logic.
    ///
    /// This `shutdown` method is required by implementors of the
    /// `AsyncWrite` trait. Wrappers typically just want to proxy this call
    /// through to the wrapped type, and base types will typically implement
    /// shutdown logic here or just return `Ok(().into())`. Note that if you're
    /// wrapping an underlying `AsyncWrite` a call to `shutdown` implies that
    /// transitively the entire stream has been shut down. After your wrapper's
    /// shutdown logic has been executed you should shut down the underlying
    /// stream.
    ///
    /// Invocation of a `shutdown` implies an invocation of `flush`. Once this
    /// method returns `Ready` it implies that a flush successfully happened
    /// before the shutdown happened. That is, callers don't need to call
    /// `flush` before calling `shutdown`. They can rely that by calling
    /// `shutdown` any pending buffered data will be written out.
    ///
    /// # Return value
    ///
    /// This function returns a `Poll<(), io::Error>` classified as such:
    ///
    /// * `Ok(Async::Ready(()))` - indicates that the connection was
    ///   successfully shut down and is now safe to deallocate/drop/close
    ///   resources associated with it. This method means that the current task
    ///   will no longer receive any notifications due to this method and the
    ///   I/O object itself is likely no longer usable.
    ///
    /// * `Ok(Async::NotReady)` - indicates that shutdown is initiated but could
    ///   not complete just yet. This may mean that more I/O needs to happen to
    ///   continue this shutdown operation. The current task is scheduled to
    ///   receive a notification when it's otherwise ready to continue the
    ///   shutdown operation. When woken up this method should be called again.
    ///
    /// * `Err(e)` - indicates a fatal error has happened with shutdown,
    ///   indicating that the shutdown operation did not complete successfully.
    ///   This typically means that the I/O object is no longer usable.
    ///
    /// # Errors
    ///
    /// This function can return normal I/O errors through `Err`, described
    /// above. Additionally this method may also render the underlying
    /// `Write::write` method no longer usable (e.g. will return errors in the
    /// future). It's recommended that once `shutdown` is called the
    /// `write` method is no longer called.
    ///
    /// # Panics
    ///
    /// This function will panic if not called within the context of a future's
    /// task.
    fn shutdown(&mut self) -> Poll<(), std_io::Error>;

    /// Write a `Buf` into this value, returning how many bytes were written.
    ///
    /// Note that this method will advance the `buf` provided automatically by
    /// the number of bytes written.
    fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
        where Self: Sized,
    {
        if !buf.has_remaining() {
            return Ok(Async::Ready(0));
        }

        let n = try_nb!(self.write(buf.bytes()));
        buf.advance(n);
        Ok(Async::Ready(n))
    }
}

impl<T: ?Sized + AsyncWrite> AsyncWrite for Box<T> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        (**self).shutdown()
    }
}
impl<'a, T: ?Sized + AsyncWrite> AsyncWrite for &'a mut T {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        (**self).shutdown()
    }
}

impl AsyncRead for std_io::Repeat {
    unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
        false
    }
}

impl AsyncWrite for std_io::Sink {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

// TODO: Implement `prepare_uninitialized_buffer` for `io::Take`.
// This is blocked on rust-lang/rust#27269
impl<T: AsyncRead> AsyncRead for std_io::Take<T> {
}

// TODO: Implement `prepare_uninitialized_buffer` when upstream exposes inner
// parts
impl<T, U> AsyncRead for std_io::Chain<T, U>
    where T: AsyncRead,
          U: AsyncRead,
{
}

impl<T: AsyncWrite> AsyncWrite for std_io::BufWriter<T> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        try_nb!(self.flush());
        self.get_mut().shutdown()
    }
}

impl<T: AsyncRead> AsyncRead for std_io::BufReader<T> {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        self.get_ref().prepare_uninitialized_buffer(buf)
    }
}

impl<T: AsRef<[u8]>> AsyncRead for std_io::Cursor<T> {
}

impl<'a> AsyncWrite for std_io::Cursor<&'a mut [u8]> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

impl AsyncWrite for std_io::Cursor<Vec<u8>> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

impl AsyncWrite for std_io::Cursor<Box<[u8]>> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

fn _assert_objects() {
    fn _assert<T>() {}
    _assert::<Box<AsyncRead>>();
    _assert::<Box<AsyncWrite>>();
}
<|endoftext|>


<commit_before>#![feature(phase)]
#![feature(macro_rules)]
#![feature(unboxed_closures)]

extern crate baps3_protocol;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::io::IoResult;
use client::{Client, Request, Response};

pub mod client;
pub mod util;

/// Creates a vector of string-slices from a vector of strings.
///
/// The slice vector lives as long as the original vector.
pub fn slicify<'a>(vec: &'a Vec<String>) -> Vec<&'a str> {
    vec.iter().map(|x| x.as_slice()).collect::<Vec<&str>>()
}

pub fn slicify_msg<'a>(code: &'a String,
                       vec: &'a Vec<String>) -> Vec<&'a str> {
    let mut v = slicify(vec);
    v.insert(0, &**code);
    v
}

pub type Logger<'a> = |&str|:'a;
#[macro_export]
macro_rules! log(
    ($l:ident, $($arg:tt)*) => (
        let _ = (*$l)(&*format!($($arg)*));
    )
)

pub fn check_baps3(log: &mut Logger,
                   Client{request_tx, response_rx}: Client)
  -> IoResult<Client> {
    'l: loop {
        match response_rx.recv_opt() {
            Ok(Response::Message(code, msg)) => {
                match &*slicify_msg(&code, &msg) {
                    ["OHAI", ident] => {
                        log!(log, "Server ident: {}", ident);
                        break 'l;
                    }
                    _ => return Err(std::io::IoError {
                        kind: std::io::IoErrorKind::OtherIoError,
                        desc: "not a BAPS3 server",
                        detail: None
                    })
                }
            },
            _ => return Err(std::io::IoError {
                kind: std::io::IoErrorKind::OtherIoError,
                desc: "unexpected response",
                detail: None
            })
        }
    }

    Ok(Client{
        request_tx: request_tx,
        response_rx: response_rx
    })
}

pub fn check_features(log: &mut Logger,
                      needed: &[&str],
                      Client{request_tx, response_rx}: Client)
  -> IoResult<Client> {
    'l: loop {
        match response_rx.recv_opt() {
            Ok(Response::Message(code, msg)) => {
                match &*slicify_msg(&code, &msg) {
                    ["FEATURES", fs..] => {
                        log!(log, "Server features: {}", fs);

                        for n in needed.iter() {
                            if !fs.contains(n) {
                                return Err(std::io::IoError {
                                    kind: std::io::IoErrorKind::OtherIoError,
                                    desc: "insufficient features",
                                    detail: Some(format!("have: {} want: {}",
                                                         fs,
                                                         needed))
                                })
                            }
                        }

                        break 'l;
                    }
                    _ => return Err(std::io::IoError {
                        kind: std::io::IoErrorKind::OtherIoError,
                        desc: "expected FEATURES here",
                        detail: None
                    })
                }
            },
            _ => return Err(std::io::IoError {
                kind: std::io::IoErrorKind::OtherIoError,
                desc: "unexpected response",
                detail: None
            })
        }
    }

    Ok(Client{
        request_tx: request_tx,
        response_rx: response_rx
    })
}

pub fn send_command(log: &mut Logger,
                    Client{request_tx, response_rx}: Client,
                    word: &str, args: &[&str])
  -> IoResult<Client> {
    log!(log, "Sending command: {} {}", word, args);

    let oword = word.into_string();
    let oargs = args.iter().map(|arg| arg.into_string()).collect();
    request_tx.send(Request::SendMessage(oword, oargs));

    'l: loop {
        match response_rx.recv_opt() {
            Ok(Response::Message(code, msg)) => {
                match &*slicify_msg(&code, &msg) {
                    ["OKAY", cword, cargs..]
                      if cword == word && cargs == args => {
                        log!(log, "success!");
                        break 'l;
                    },
                    ["WHAT", advice, cword, cargs..]
                      if cword == word && cargs == args => {
                        werr!("command invalid: {}", advice);
                        break 'l;
                    },
                    ["FAIL", advice, cword, cargs..]
                      if cword == word && cargs == args => {
                        werr!("command failed: {}", advice);
                        break 'l;
                    },
                    _ => ()
                }
            },
            _ => return Err(std::io::IoError {
                kind: std::io::IoErrorKind::OtherIoError,
                desc: "unexpected response",
                detail: None
            })
        }
    }

    Ok(Client{
        request_tx: request_tx,
        response_rx: response_rx
    })
}

pub fn quit_client(log: &mut Logger, Client{request_tx, ..}: Client)
  -> IoResult<()> {
    log!(log, "Closing client connection");

    request_tx.send(Request::Quit);
    Ok(())
}

/// A one-shot BAPS3 request.
///
/// This takes a server connection and performs the following:
///   - Checks that the server is a BAPS3 server, by seeing if an OHAI line is
///     being received;
///   - Checks the server's FEATURES flags against `features`, and fails if
///     any are missing;
///   - Sends the command `word` `args`;
///   - Reads until the server sends an OKAY, FAIL, or WHAT response for that
///     command.
pub fn one_shot(log: &mut Logger,
            client: Client,
            features: &[&str],
            word: &str,
            args: &[&str])
  -> IoResult<()> {
    check_baps3(log, client)
      .and_then(|c| check_features(log, features, c))
      .and_then(|c| send_command(log, c, word, args))
      .and_then(|c| quit_client(log, c))
}

/// Creates a Logger from the -v/--verbose flag of a command.
///
/// If verbose is on (-v/--verbose == true), we dump log messages to stderr,
/// else we ignore them.
pub fn verbose_logger<'a>(verbose: bool) -> Logger<'a> {
    if verbose { |s: &str| { let _ = std::io::stderr().write_line(s); } }
    else       { |_| {} }
}<commit_msg>OKAY -> OK<commit_after>#![feature(phase)]
#![feature(macro_rules)]
#![feature(unboxed_closures)]

extern crate baps3_protocol;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::io::IoResult;
use client::{Client, Request, Response};

pub mod client;
pub mod util;

/// Creates a vector of string-slices from a vector of strings.
///
/// The slice vector lives as long as the original vector.
pub fn slicify<'a>(vec: &'a Vec<String>) -> Vec<&'a str> {
    vec.iter().map(|x| x.as_slice()).collect::<Vec<&str>>()
}

pub fn slicify_msg<'a>(code: &'a String,
                       vec: &'a Vec<String>) -> Vec<&'a str> {
    let mut v = slicify(vec);
    v.insert(0, &**code);
    v
}

pub type Logger<'a> = |&str|:'a;
#[macro_export]
macro_rules! log(
    ($l:ident, $($arg:tt)*) => (
        let _ = (*$l)(&*format!($($arg)*));
    )
)

pub fn check_baps3(log: &mut Logger,
                   Client{request_tx, response_rx}: Client)
  -> IoResult<Client> {
    'l: loop {
        match response_rx.recv_opt() {
            Ok(Response::Message(code, msg)) => {
                match &*slicify_msg(&code, &msg) {
                    ["OHAI", ident] => {
                        log!(log, "Server ident: {}", ident);
                        break 'l;
                    }
                    _ => return Err(std::io::IoError {
                        kind: std::io::IoErrorKind::OtherIoError,
                        desc: "not a BAPS3 server",
                        detail: None
                    })
                }
            },
            _ => return Err(std::io::IoError {
                kind: std::io::IoErrorKind::OtherIoError,
                desc: "unexpected response",
                detail: None
            })
        }
    }

    Ok(Client{
        request_tx: request_tx,
        response_rx: response_rx
    })
}

pub fn check_features(log: &mut Logger,
                      needed: &[&str],
                      Client{request_tx, response_rx}: Client)
  -> IoResult<Client> {
    'l: loop {
        match response_rx.recv_opt() {
            Ok(Response::Message(code, msg)) => {
                match &*slicify_msg(&code, &msg) {
                    ["FEATURES", fs..] => {
                        log!(log, "Server features: {}", fs);

                        for n in needed.iter() {
                            if !fs.contains(n) {
                                return Err(std::io::IoError {
                                    kind: std::io::IoErrorKind::OtherIoError,
                                    desc: "insufficient features",
                                    detail: Some(format!("have: {} want: {}",
                                                         fs,
                                                         needed))
                                })
                            }
                        }

                        break 'l;
                    }
                    _ => return Err(std::io::IoError {
                        kind: std::io::IoErrorKind::OtherIoError,
                        desc: "expected FEATURES here",
                        detail: None
                    })
                }
            },
            _ => return Err(std::io::IoError {
                kind: std::io::IoErrorKind::OtherIoError,
                desc: "unexpected response",
                detail: None
            })
        }
    }

    Ok(Client{
        request_tx: request_tx,
        response_rx: response_rx
    })
}

pub fn send_command(log: &mut Logger,
                    Client{request_tx, response_rx}: Client,
                    word: &str, args: &[&str])
  -> IoResult<Client> {
    log!(log, "Sending command: {} {}", word, args);

    let oword = word.into_string();
    let oargs = args.iter().map(|arg| arg.into_string()).collect();
    request_tx.send(Request::SendMessage(oword, oargs));

    'l: loop {
        match response_rx.recv_opt() {
            Ok(Response::Message(code, msg)) => {
                match &*slicify_msg(&code, &msg) {
                    ["OK", cword, cargs..]
                      if cword == word && cargs == args => {
                        log!(log, "success!");
                        break 'l;
                    },
                    ["WHAT", advice, cword, cargs..]
                      if cword == word && cargs == args => {
                        werr!("command invalid: {}", advice);
                        break 'l;
                    },
                    ["FAIL", advice, cword, cargs..]
                      if cword == word && cargs == args => {
                        werr!("command failed: {}", advice);
                        break 'l;
                    },
                    _ => ()
                }
            },
            _ => return Err(std::io::IoError {
                kind: std::io::IoErrorKind::OtherIoError,
                desc: "unexpected response",
                detail: None
            })
        }
    }

    Ok(Client{
        request_tx: request_tx,
        response_rx: response_rx
    })
}

pub fn quit_client(log: &mut Logger, Client{request_tx, ..}: Client)
  -> IoResult<()> {
    log!(log, "Closing client connection");

    request_tx.send(Request::Quit);
    Ok(())
}

/// A one-shot BAPS3 request.
///
/// This takes a server connection and performs the following:
///   - Checks that the server is a BAPS3 server, by seeing if an OHAI line is
///     being received;
///   - Checks the server's FEATURES flags against `features`, and fails if
///     any are missing;
///   - Sends the command `word` `args`;
///   - Reads until the server sends an OKAY, FAIL, or WHAT response for that
///     command.
pub fn one_shot(log: &mut Logger,
            client: Client,
            features: &[&str],
            word: &str,
            args: &[&str])
  -> IoResult<()> {
    check_baps3(log, client)
      .and_then(|c| check_features(log, features, c))
      .and_then(|c| send_command(log, c, word, args))
      .and_then(|c| quit_client(log, c))
}

/// Creates a Logger from the -v/--verbose flag of a command.
///
/// If verbose is on (-v/--verbose == true), we dump log messages to stderr,
/// else we ignore them.
pub fn verbose_logger<'a>(verbose: bool) -> Logger<'a> {
    if verbose { |s: &str| { let _ = std::io::stderr().write_line(s); } }
    else       { |_| {} }
}<|endoftext|>


<commit_before>//! Please contact me on github and file any issues if you find some, I'm also open to PRs or other suggestions.
//!
//! Updated to Tera 0.10 / Serde 1.0 / Iron 0.5 !
//! Serde 0.9.0 to_value returns a `Result`, this means you need to handle the possiblity of a serialization failure.
//! If you just want to `unwrap()` there is an implementation of From<Value> for TemplateMode so `Template::new(path, value)`
//! works also.
//!
//! **update iron-tera-0.4.0**: If you build this crate with feature = "unstable" on the nightly compiler,
//! I've included a `TryFrom` impl to improve API ergonomics. Instead of
//! `TemplateMode::from_serial` use `value.try_into()`. This uses the `TryFrom` feature to return a fallible `Result`.
//!
//! ## Examples
//! The following is a complete working example that I've tested with serde 0.9.0, tera 0.7.0 and iron-tera 0.2.0
//!
//! ```ignore
//!   [dependencies]
//!   iron-tera = { version = "0.4.0" }  # optional:  features = [ "unstable" ]
//! ```
//!
//! Using `iron-tera` stable.
//! ```ignore
//! extern crate tera;
//! extern crate iron;
//! extern crate router;
//! #[macro_use] extern crate serde_json;
//! #[macro_use] extern crate serde_derive;
//! extern crate iron_tera;
//!
//! use iron::prelude::*;
//! use iron::status;
//! use router::Router;
//! use tera::Context;
//!
//! use iron_tera::{Template, TeraEngine}; // import TemplateMode to explicitly handle serialization errors
//! fn main() {
//!
//!     let mut router = Router::new();
//!     router.get("/context", context_handler, "context");
//!     router.get("/json", json_handler, "json");
//!
//!     let mut chain = Chain::new(router);
//!     let teng = TeraEngine::new("src/examples/templates/**/*");
//!     chain.link_after(teng);
//!
//!     Iron::new(chain).http("localhost:5000").unwrap();
//!
//!
//!     fn context_handler(_: &mut Request) -> IronResult<Response> {
//!         let mut resp = Response::new();
//!
//!         let mut context = Context::new();
//!         context.add("username", &"Bob");
//!         context.add("my_var", &"Thing"); // comment out to see alternate thing
//!         context.add("numbers", &vec![1, 2, 3]);
//!         context.add("bio", &"<script>alert('pwnd');</script>");
//!
//!         // can use Template::new(path, TemplateMode::from_context(context)) or TemplateMode::from(context) also
//!         resp.set_mut(Template::new("users/profile.html", context))
//!             .set_mut(status::Ok);
//!         Ok(resp)
//!     }
//!     fn json_handler(_: &mut Request) -> IronResult<Response> {
//!         let mut resp = Response::new();
//!
//!         let blob = json!({
//!             "username": "John Doe",
//!             "my_var": "Thing",
//!             "numbers": [
//!                 "1",
//!                 "+44 2345678",
//!                 "3"
//!             ],
//!             "bio": "<script>alert('pwnd');</script>"
//!          });
//!         // you can use blob.try_into() and handle the `Result` explicitly (not shown here)
//!         // on the `unstable` feature of `iron-tera`
//!         resp.set_mut(Template::new("users/profile.html", blob))
//!             .set_mut(status::Ok);
//!         Ok(resp)
//!     }
//! }
//! ```
//!
//! Creating a template from a struct
//!
//! ```ignore
//! // The following uses serde's Serialize
//! #[derive(Serialize)]
//! struct Product {
//!     name: String,
//!     value: i32,
//! }
//! // Rendering from a struct that implements Serialize
//! fn produce_handler(_: &mut Request) -> IronResult<Response> {
//!     let mut resp = Response::new();
//!
//!     // Using serialized values
//!     let product = Product {
//!         name: "Foo".into(),
//!         value: 42,
//!     };
//!     // You can use TemplateMode::from()
//!     resp.set_mut(Template::new("product.html", product))
//!         .set_mut(status::Ok);
//!     Ok(resp)
//! }
//! ```
#![cfg_attr(feature = "unstable", feature(try_from))]

#![allow(dead_code)]
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate tera;
extern crate iron;
extern crate serde;
extern crate plugin;

use iron::{AfterMiddleware, status, typemap};
use iron::headers::ContentType;
use iron::modifier::Modifier;
use iron::prelude::*;

use plugin::Plugin;

use serde::ser::Serialize;
use serde_json::{Value, to_value};

#[cfg(feature = "unstable")]
use std::convert::{TryFrom, TryInto};
use std::convert::From;

use tera::{Context, Tera};

/// There are 2 main ways to pass data to generate a template.
#[derive(Clone)]
pub enum TemplateMode {
    /// TeraContext constructor takes a `Context`
    TeraContext(Context),
    /// Serialized constructor takes a `Value` from `serde_json`
    Serialized(Value),
}

/// TemplateMode should only ever be created from these smart constructors,
/// not with the enums type constructors.
impl TemplateMode {
    pub fn from_context(context: Context) -> TemplateMode {
        TemplateMode::TeraContext(context)
    }

    #[cfg(feature = "unstable")]
    pub fn try_serialize<S: Serialize>(
        serializeable: S,
    ) -> Result<TemplateMode, serde_json::Error> {
        Ok(serializeable.try_into()?)
    }

    #[cfg(not(feature = "unstable"))]
    pub fn from_serial<S: Serialize>(serializeable: S) -> Result<TemplateMode, serde_json::Error> {
        Ok(TemplateMode::Serialized(to_value(serializeable)?))
    }
}

impl From<Context> for TemplateMode {
    fn from(context: Context) -> Self {
        TemplateMode::from_context(context)
    }
}

#[cfg(not(feature = "unstable"))]
impl From<Value> for TemplateMode {
    fn from(serializeable: Value) -> Self {
        TemplateMode::from_serial(serializeable).unwrap()
    }
}

#[cfg(feature = "unstable")]
impl<S> TryFrom<S> for TemplateMode
where
    S: Serialize,
{
    type Error = serde_json::Error;
    fn try_from(value: S) -> Result<Self, Self::Error> {
        from_serde(value)
    }
}

#[cfg(feature = "unstable")]
fn from_serde<S: Serialize>(serializeable: S) -> Result<TemplateMode, serde_json::Error> {
    Ok(TemplateMode::Serialized(to_value(serializeable)?))
}

/// Our template holds a name (path to template) and a mode (constructed with `from_context` or `from_serial`)
#[derive(Clone)]
pub struct Template {
    mode: TemplateMode,
    name: String,
}

impl Template {
    #[cfg(not(feature = "unstable"))]
    pub fn new<T: Into<TemplateMode>, S: Into<String>>(name: S, mode: T) -> Template {
        Template {
            name: name.into(),
            mode: mode.into(),
        }
    }
    #[cfg(feature = "unstable")]
    pub fn new<S: Into<String>>(name: S, mode: TemplateMode) -> Template {
        Template {
            name: name.into(),
            mode,
        }
    }
}

/// TeraEngine holds the Tera struct so that it can be used by many handlers without explicitly passing
pub struct TeraEngine {
    pub tera: Tera,
}

/// `compile_templates!` is used to parse the contents of a dir for all templates.
impl TeraEngine {
    /// Take a `String` and convert to a slice
    pub fn new<S: AsRef<str>>(dir: S) -> TeraEngine {
        TeraEngine { tera: compile_templates!(dir.as_ref()) }
    }
}

impl typemap::Key for TeraEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<TeraEngine>(self);
    }
}

/// The middleware implementation for TeraEngine
impl AfterMiddleware for TeraEngine {
    /// This is where all the magic happens. We extract `TeraEngine` from Iron's `Response`,
    /// determine what `TemplateMode` we should render in, and pass the appropriate values to
    /// tera's render methods.
    fn after(&self, _: &mut Request, mut resp: Response) -> IronResult<Response> {
        let wrapper = resp.extensions.remove::<TeraEngine>().and_then(
            |t| match t.mode {
                TemplateMode::TeraContext(ref context) => Some(self.tera.render(&t.name, context)),
                TemplateMode::Serialized(ref value) => Some(self.tera.render(&t.name, value)),
            },
        );
        match wrapper {
            Some(result) => {
                result
                    .map_err(|e| IronError::new(e, status::InternalServerError))
                    .and_then(|page| {
                        if !resp.headers.has::<ContentType>() {
                            resp.headers.set(ContentType::html());
                        }
                        resp.set_mut(page);
                        Ok(resp)
                    })
            }
            None => Ok(resp),
        }
    }

    fn catch(&self, req: &mut Request, mut err: IronError) -> IronResult<Response> {
        err.response = self.after(req, err.response)?;
        Err(err)
    }
}

impl Plugin<Response> for TeraEngine {
    type Error = ();

    fn eval(resp: &mut Response) -> Result<Template, ()> {
        match resp.extensions.get::<TeraEngine>() {
            Some(t) => Ok(t.clone()),
            None => Err(()),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Template, TemplateMode, TeraEngine};
    use iron::prelude::*;
    use tera::Context;

    fn from_context_response() -> IronResult<Response> {
        let resp = Response::new();
        let mut context = Context::new();
        context.add("greeting", &"hi!");
        Ok(resp.set(
            Template::new("./test_template/users/foo.html", context),
        ))
    }

    #[test]
    fn test_from_context() {
        let mut resp = from_context_response().ok().expect("response expected");
        match resp.get::<TeraEngine>() {
            Ok(h) => {
                assert_eq!(h.name, "./test_template/users/foo.html".to_string());
                if let TemplateMode::TeraContext(context) = h.mode {
                    assert_eq!(
                        context
                            .as_json()
                            .unwrap()
                            .get("greeting")
                            .unwrap()
                            .as_str()
                            .unwrap(),
                        "hi!"
                    );
                } else {
                    panic!("TeraContext expected");
                }
            }
            _ => panic!("template expected"),
        }
    }
}
<commit_msg>Fixed docs<commit_after>//! Please contact me on github and file any issues if you find some, I'm also open to PRs or other suggestions.
//!
//! Updated to Tera 0.10 / Serde 1.0 / Iron 0.5 !
//! Serde 0.9.0 to_value returns a `Result`, this means you need to handle the possiblity of a serialization failure.
//! If you just want to `unwrap()` there is an implementation of From<Value> for TemplateMode so `Template::new(path, value)`
//! works also.
//!
//! **update iron-tera-0.4.0**: If you build this crate with feature = "unstable" on the nightly compiler,
//! I've included a `TryFrom` impl to improve API ergonomics. Instead of
//! `TemplateMode::from_serial` use `value.try_into()`. This uses the `TryFrom` feature to return a fallible `Result`.
//!
//! ## Examples
//! The following is a complete working example that I've tested with serde 0.9.0, tera 0.7.0 and iron-tera 0.2.0
//!
//! ```ignore
//!   [dependencies]
//!   iron-tera = { version = "0.4.0" }  # optional:  features = [ "unstable" ]
//! ```
//!
//! Using `iron-tera` stable.
//!
//! ```ignore
//! extern crate tera;
//! extern crate iron;
//! extern crate router;
//! #[macro_use] extern crate serde_json;
//! #[macro_use] extern crate serde_derive;
//! extern crate iron_tera;
//!
//! use iron::prelude::*;
//! use iron::status;
//! use router::Router;
//! use tera::Context;
//!
//! use iron_tera::{Template, TeraEngine}; // import TemplateMode to explicitly handle serialization errors
//! fn main() {
//!
//!     let mut router = Router::new();
//!     router.get("/context", context_handler, "context");
//!     router.get("/json", json_handler, "json");
//!
//!     let mut chain = Chain::new(router);
//!     let teng = TeraEngine::new("src/examples/templates/**/*");
//!     chain.link_after(teng);
//!
//!     Iron::new(chain).http("localhost:5000").unwrap();
//!
//!
//!     fn context_handler(_: &mut Request) -> IronResult<Response> {
//!         let mut resp = Response::new();
//!
//!         let mut context = Context::new();
//!         context.add("username", &"Bob");
//!         context.add("my_var", &"Thing"); // comment out to see alternate thing
//!         context.add("numbers", &vec![1, 2, 3]);
//!         context.add("bio", &"<script>alert('pwnd');</script>");
//!
//!         // can use Template::new(path, TemplateMode::from_context(context)) or TemplateMode::from(context) also
//!         resp.set_mut(Template::new("users/profile.html", context))
//!             .set_mut(status::Ok);
//!         Ok(resp)
//!     }
//!     fn json_handler(_: &mut Request) -> IronResult<Response> {
//!         let mut resp = Response::new();
//!
//!         let blob = json!({
//!             "username": "John Doe",
//!             "my_var": "Thing",
//!             "numbers": [
//!                 "1",
//!                 "+44 2345678",
//!                 "3"
//!             ],
//!             "bio": "<script>alert('pwnd');</script>"
//!          });
//!         // you can use blob.try_into() and handle the `Result` explicitly (not shown here)
//!         // on the `unstable` feature of `iron-tera`
//!         resp.set_mut(Template::new("users/profile.html", blob))
//!             .set_mut(status::Ok);
//!         Ok(resp)
//!     }
//! }
//! ```
//!
//! Creating a template from a struct
//!
//! ```ignore
//! // The following uses serde's Serialize
//! #[derive(Serialize)]
//! struct Product {
//!     name: String,
//!     value: i32,
//! }
//! // Rendering from a struct that implements Serialize
//! fn produce_handler(_: &mut Request) -> IronResult<Response> {
//!     let mut resp = Response::new();
//!
//!     // Using serialized values
//!     let product = Product {
//!         name: "Foo".into(),
//!         value: 42,
//!     };
//!     // You can use TemplateMode::from()
//!     resp.set_mut(Template::new("product.html", product))
//!         .set_mut(status::Ok);
//!     Ok(resp)
//! }
//! ```
#![cfg_attr(feature = "unstable", feature(try_from))]

#![allow(dead_code)]
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate tera;
extern crate iron;
extern crate serde;
extern crate plugin;

use iron::{AfterMiddleware, status, typemap};
use iron::headers::ContentType;
use iron::modifier::Modifier;
use iron::prelude::*;

use plugin::Plugin;

use serde::ser::Serialize;
use serde_json::{Value, to_value};

#[cfg(feature = "unstable")]
use std::convert::{TryFrom, TryInto};
use std::convert::From;

use tera::{Context, Tera};

/// There are 2 main ways to pass data to generate a template.
#[derive(Clone)]
pub enum TemplateMode {
    /// TeraContext constructor takes a `Context`
    TeraContext(Context),
    /// Serialized constructor takes a `Value` from `serde_json`
    Serialized(Value),
}

/// TemplateMode should only ever be created from these smart constructors,
/// not with the enums type constructors.
impl TemplateMode {
    pub fn from_context(context: Context) -> TemplateMode {
        TemplateMode::TeraContext(context)
    }

    #[cfg(feature = "unstable")]
    pub fn try_serialize<S: Serialize>(
        serializeable: S,
    ) -> Result<TemplateMode, serde_json::Error> {
        Ok(serializeable.try_into()?)
    }

    #[cfg(not(feature = "unstable"))]
    pub fn from_serial<S: Serialize>(serializeable: S) -> Result<TemplateMode, serde_json::Error> {
        Ok(TemplateMode::Serialized(to_value(serializeable)?))
    }
}

impl From<Context> for TemplateMode {
    fn from(context: Context) -> Self {
        TemplateMode::from_context(context)
    }
}

#[cfg(not(feature = "unstable"))]
impl From<Value> for TemplateMode {
    fn from(serializeable: Value) -> Self {
        TemplateMode::from_serial(serializeable).unwrap()
    }
}

#[cfg(feature = "unstable")]
impl<S> TryFrom<S> for TemplateMode
where
    S: Serialize,
{
    type Error = serde_json::Error;
    fn try_from(value: S) -> Result<Self, Self::Error> {
        from_serde(value)
    }
}

#[cfg(feature = "unstable")]
fn from_serde<S: Serialize>(serializeable: S) -> Result<TemplateMode, serde_json::Error> {
    Ok(TemplateMode::Serialized(to_value(serializeable)?))
}

/// Our template holds a name (path to template) and a mode (constructed with `from_context` or `from_serial`)
#[derive(Clone)]
pub struct Template {
    mode: TemplateMode,
    name: String,
}

impl Template {
    #[cfg(not(feature = "unstable"))]
    pub fn new<T: Into<TemplateMode>, S: Into<String>>(name: S, mode: T) -> Template {
        Template {
            name: name.into(),
            mode: mode.into(),
        }
    }
    #[cfg(feature = "unstable")]
    pub fn new<S: Into<String>>(name: S, mode: TemplateMode) -> Template {
        Template {
            name: name.into(),
            mode,
        }
    }
}

/// TeraEngine holds the Tera struct so that it can be used by many handlers without explicitly passing
pub struct TeraEngine {
    pub tera: Tera,
}

/// `compile_templates!` is used to parse the contents of a dir for all templates.
impl TeraEngine {
    /// Take a `String` and convert to a slice
    pub fn new<S: AsRef<str>>(dir: S) -> TeraEngine {
        TeraEngine { tera: compile_templates!(dir.as_ref()) }
    }
}

impl typemap::Key for TeraEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<TeraEngine>(self);
    }
}

/// The middleware implementation for TeraEngine
impl AfterMiddleware for TeraEngine {
    /// This is where all the magic happens. We extract `TeraEngine` from Iron's `Response`,
    /// determine what `TemplateMode` we should render in, and pass the appropriate values to
    /// tera's render methods.
    fn after(&self, _: &mut Request, mut resp: Response) -> IronResult<Response> {
        let wrapper = resp.extensions.remove::<TeraEngine>().and_then(
            |t| match t.mode {
                TemplateMode::TeraContext(ref context) => Some(self.tera.render(&t.name, context)),
                TemplateMode::Serialized(ref value) => Some(self.tera.render(&t.name, value)),
            },
        );
        match wrapper {
            Some(result) => {
                result
                    .map_err(|e| IronError::new(e, status::InternalServerError))
                    .and_then(|page| {
                        if !resp.headers.has::<ContentType>() {
                            resp.headers.set(ContentType::html());
                        }
                        resp.set_mut(page);
                        Ok(resp)
                    })
            }
            None => Ok(resp),
        }
    }

    fn catch(&self, req: &mut Request, mut err: IronError) -> IronResult<Response> {
        err.response = self.after(req, err.response)?;
        Err(err)
    }
}

impl Plugin<Response> for TeraEngine {
    type Error = ();

    fn eval(resp: &mut Response) -> Result<Template, ()> {
        match resp.extensions.get::<TeraEngine>() {
            Some(t) => Ok(t.clone()),
            None => Err(()),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Template, TemplateMode, TeraEngine};
    use iron::prelude::*;
    use tera::Context;

    fn from_context_response() -> IronResult<Response> {
        let resp = Response::new();
        let mut context = Context::new();
        context.add("greeting", &"hi!");
        Ok(resp.set(
            Template::new("./test_template/users/foo.html", context),
        ))
    }

    #[test]
    fn test_from_context() {
        let mut resp = from_context_response().ok().expect("response expected");
        match resp.get::<TeraEngine>() {
            Ok(h) => {
                assert_eq!(h.name, "./test_template/users/foo.html".to_string());
                if let TemplateMode::TeraContext(context) = h.mode {
                    assert_eq!(
                        context
                            .as_json()
                            .unwrap()
                            .get("greeting")
                            .unwrap()
                            .as_str()
                            .unwrap(),
                        "hi!"
                    );
                } else {
                    panic!("TeraContext expected");
                }
            }
            _ => panic!("template expected"),
        }
    }
}
<|endoftext|>


<commit_before>mod trie;

use std::collections::HashMap;

const BASE_UNITS: [(&'static str, u16); 30] = [
    ("A", 0), ("T", 1), ("C", 2), ("G", 3), ("N", 4),
    ("AA", 5), ("AT", 6), ("AC", 7), ("AG", 8), ("AN", 9),
    ("TA", 10), ("TT", 11), ("TC", 12), ("TG", 13), ("TN", 14),
    ("CA", 15), ("CT", 16), ("CC", 17), ("CG", 18), ("CN", 19),
    ("GA", 20), ("GT", 21), ("GC", 22), ("GG", 23), ("GN", 24),
    ("NA", 25), ("NT", 26), ("NC", 27), ("NG", 28), ("NN", 29),
];

// 5 bits (per base unit) * 3 units = 15 bits (to store in `u16`)
const BITS_SIZE: u16 = 5;
const NUM_UNITS: usize = 3;

pub use trie::Trie as Trie;

fn shift_bits(chunk: &[u16]) -> u16 {
    let mut shifted = chunk[0];
    for i in 1..chunk.len() {
        shifted = (shifted << BITS_SIZE) | chunk[i];
    }

    shifted
}

#[derive(Debug)]
pub struct SequenceTrie<T> {
    // Underlying Trie with bit-mapped bases. Instead of having individual bases
    // in every level, we have a 16-bit integer that can hold 6 bases at a time
    // (or 5, if the sequence has an 'odd' length), which is somewhat space-efficient.
    trie: Trie<u16, T>,
    base_map: HashMap<&'static str, u16>,
}

impl<T> SequenceTrie<T> {
    pub fn new() -> SequenceTrie<T> {
        SequenceTrie {
            trie: Trie::new(),
            base_map: BASE_UNITS.iter().cloned().collect(),
        }
    }

    fn get_mapped_vec(&self, seq: &str) -> Vec<u16> {
        let mut vec = (0..(seq.len() / 2)).map(|i| {
            let chunk = &seq[(i * 2)..((i + 1) * 2)];
            *self.base_map.get(chunk).unwrap()
        }).collect::<Vec<_>>();

        if seq.len() % 2 != 0 {
            let base = &seq[(seq.len() - 1)..];
            vec.push(*self.base_map.get(base).unwrap());
        }

        vec
    }

    pub fn insert(&mut self, seq: &str, value: T) {
        let vec = self.get_mapped_vec(seq);
        self.trie.insert(vec.chunks(NUM_UNITS).into_iter().map(shift_bits), value);
    }

    pub fn get(&self, seq: &str) -> Option<&T> {
        let vec = self.get_mapped_vec(seq);
        self.trie.get(vec.chunks(NUM_UNITS).into_iter().map(shift_bits), false)
    }

    pub fn get_unique(&self, seq: &str) -> Option<&T> {
        let vec = self.get_mapped_vec(seq);
        self.trie.get(vec.chunks(NUM_UNITS).into_iter().map(shift_bits), true)
    }
}
<commit_msg>Store all 15 kinds of base representations (8 bases in u32)<commit_after>mod trie;

use std::collections::HashMap;

const BASES: &'static str = "ATCGNYRWSKMDVHB";

// 4 bits (per base unit) * 8 units = 32 bits (to store in `u32`)
const BITS_SIZE: u32 = 4;
const NUM_UNITS: usize = 8;

pub use trie::Trie as Trie;

fn shift_bits(chunk: &[u32]) -> u32 {
    let mut shifted = chunk[0];
    for i in 1..chunk.len() {
        shifted = (shifted << BITS_SIZE) | chunk[i];
    }

    shifted
}

#[derive(Debug)]
pub struct SequenceTrie<T> {
    // Underlying Trie with bit-mapped bases. Instead of having individual bases
    // in every level, we have a 32-bit integer that can hold 8 bases at a time
    // which is somewhat space-efficient.
    trie: Trie<u32, T>,
    base_map: HashMap<&'static str, u32>,
}

impl<T> SequenceTrie<T> {
    pub fn new() -> SequenceTrie<T> {
        SequenceTrie {
            trie: Trie::new(),
            base_map: (0..BASES.len()).map(|i| (&BASES[i..(i + 1)], i as u32))
                                      .collect::<HashMap<_, _>>(),
        }
    }

    fn get_mapped_vec(&self, seq: &str) -> Vec<u32> {
        (0..seq.len()).map(|i| {
            let chunk = &seq[i..(i + 1)];
            *self.base_map.get(chunk).unwrap()
        }).collect::<Vec<_>>()
    }

    pub fn insert(&mut self, seq: &str, value: T) {
        let vec = self.get_mapped_vec(seq);
        self.trie.insert(vec.chunks(NUM_UNITS).into_iter().map(shift_bits), value);
    }

    pub fn get(&self, seq: &str) -> Option<&T> {
        let vec = self.get_mapped_vec(seq);
        self.trie.get(vec.chunks(NUM_UNITS).into_iter().map(shift_bits), false)
    }

    pub fn get_unique(&self, seq: &str) -> Option<&T> {
        let vec = self.get_mapped_vec(seq);
        self.trie.get(vec.chunks(NUM_UNITS).into_iter().map(shift_bits), true)
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;

use std::sync::atomic;
use std::sync::atomic::Ordering;
use std::ptr;

const KEYSZ: usize = 16;
const INITIAL_SIZE: usize = 128;

type HashKey = Box<[u8; 16]>;

#[derive(Debug)]
struct HashSlot {
    key: atomic::AtomicPtr<HashKey>,
    count: atomic::AtomicUsize,
}

impl HashSlot {
    pub fn new() -> HashSlot {
        HashSlot {
            key: atomic::AtomicPtr::new(ptr::null_mut()),
            count: atomic::AtomicUsize::new(0),
        }
    }
}

pub struct Counter {
    size: usize,
    used: atomic::AtomicUsize,
    slots: Vec<HashSlot>,
    prev: atomic::AtomicPtr<Counter>,
    next: atomic:: AtomicPtr<Counter>,
}

fn djb2_hash(key: &HashKey) -> usize {
    let start: usize = 5381;
    key.into_iter().take_while(|c| { **c != 0 }).fold(start, |hash, c| {
        (hash * 33) ^ (*c as usize)})
}

#[inline]
fn is_ascii(c: &u8) -> bool {
    return (*c > 47 && *c < 58) || (*c > 64 && *c < 91) || (*c > 96 && *c < 123);
}

fn clean_key(key: &str) -> HashKey {
    let mut cleaned: HashKey = Box::new([0; 16]);
    for (index, v) in key.bytes().take(16).filter(is_ascii).enumerate() {
        cleaned[index] = v;
    }
    return cleaned;
}

impl Counter {
    pub fn new() -> Counter {
        let mut slots: Vec<HashSlot> = Vec::with_capacity(INITIAL_SIZE);
        for _ in 0..INITIAL_SIZE {
            slots.push(HashSlot::new());
        }
        let counter: Counter = Counter {
            size: INITIAL_SIZE,
            used: atomic::AtomicUsize::new(0),
            slots: slots,
            prev: atomic::AtomicPtr::new(ptr::null_mut()),
            next: atomic::AtomicPtr::new(ptr::null_mut()),
        };
        return counter;
    }

    unsafe fn print_slot(&self, index: usize) {
        let slot = &self.slots[index];
        let key = slot.key.load(Ordering::Relaxed);
        println!("slot {}: {:?}", index, slot);
        if key.is_null() {
            println!("\t key=null")
        }
        else {
            println!("\t key={:?}", *key);
        }
    }

    unsafe fn unsafe_get(&self, key: HashKey) -> usize {
        let size = self.size;
        let mut index = djb2_hash(&key) % size;
        loop {
            let slot = &self.slots[index];
            let other_key = slot.key.load(Ordering::Relaxed);
            if other_key.is_null() {
                return 0;
            }
            else if *other_key == key {
                return slot.count.load(Ordering::Relaxed);
            }
            index = (index + 1) % size;
        }
    }

    unsafe fn unsafe_incr(&mut self, mut key: HashKey, count: usize) -> usize {
        let size = self.size;
        let mut index = djb2_hash(&key) % size;
        loop {
            let slot = &self.slots[index];
            let other_key = slot.key.load(Ordering::Relaxed);
            if other_key.is_null() {
                let res = slot.key.compare_exchange(other_key,
                                                    &mut key,
                                                    Ordering::Relaxed,
                                                    Ordering::Relaxed);
                let status = match res {
                    Ok(v) => v.is_null() || *v == key,
                    Err(v) => v.is_null() || *v == key,
                };
                if status {
                    self.used.fetch_add(1, Ordering::Relaxed);
                    //TODO(rossdylan) handle resizing
                    let added = slot.count.fetch_add(count, Ordering::Relaxed);
                    return added
                }
            }
            else if *other_key == key {
                return slot.count.fetch_add(count, Ordering::Relaxed);
            }
            index = (index + 1) % size
        }
    }

    pub fn incr(&mut self, key: &str, count: usize) -> usize {
        return unsafe { self.unsafe_incr(clean_key(key), count) };
    }

    pub fn get(&self, key: &str) -> usize {
        return unsafe { self.unsafe_get(clean_key(key)) };
    }
}

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

    #[test]
    fn increment() {
        let mut counter = Counter::new();
        let res = counter.incr("foo", 1);
        assert_eq!(res, 0);
    }

    #[test]
    fn get() {
        let mut counter = Counter::new();
        let res = counter.incr("foo", 1);
        let count = counter.get("foo");
        assert_eq!(count, 1);
    }

    #[bench]
    fn bench_incr(b: &mut Bencher) {
        let mut counter = Counter::new();
        b.iter(|| counter.incr("foo", 1))
    }

    #[bench]
    fn bench_get(b: &mut Bencher) {
        let mut counter = Counter::new();
        counter.incr("foo", 100);
        b.iter(|| counter.get("foo"))
    }
}
<commit_msg>Fixed more pointer isues when storing new keys in the map<commit_after>#![feature(test)]
extern crate test;

use std::sync::atomic;
use std::sync::atomic::Ordering;
use std::ptr;

const KEYSZ: usize = 16;
const INITIAL_SIZE: usize = 128;

type RawKey = [u8; 16];
type HashKey = Box<RawKey>;

#[derive(Debug)]
struct HashSlot {
    key: atomic::AtomicPtr<RawKey>,
    count: atomic::AtomicUsize,
}

impl HashSlot {
    pub fn new() -> HashSlot {
        HashSlot {
            key: atomic::AtomicPtr::new(ptr::null_mut()),
            count: atomic::AtomicUsize::new(0),
        }
    }
}

pub struct Counter {
    size: usize,
    used: atomic::AtomicUsize,
    slots: Vec<HashSlot>,
    prev: atomic::AtomicPtr<Counter>,
    next: atomic:: AtomicPtr<Counter>,
}

fn djb2_hash(key: &HashKey) -> usize {
    let start: usize = 5381;
    key.into_iter().take_while(|c| { **c != 0 }).fold(start, |hash, c| {
        (hash * 33) ^ (*c as usize)})
}

#[inline]
fn is_ascii(c: &u8) -> bool {
    return (*c > 47 && *c < 58) || (*c > 64 && *c < 91) || (*c > 96 && *c < 123);
}

fn clean_key(key: &str) -> HashKey {
    let mut cleaned: HashKey = Box::new([0; 16]);
    for (index, v) in key.bytes().take(16).filter(is_ascii).enumerate() {
        cleaned[index] = v;
    }
    return cleaned;
}

impl Counter {
    pub fn new() -> Counter {
        let mut slots: Vec<HashSlot> = Vec::with_capacity(INITIAL_SIZE);
        for _ in 0..INITIAL_SIZE {
            slots.push(HashSlot::new());
        }
        let counter: Counter = Counter {
            size: INITIAL_SIZE,
            used: atomic::AtomicUsize::new(0),
            slots: slots,
            prev: atomic::AtomicPtr::new(ptr::null_mut()),
            next: atomic::AtomicPtr::new(ptr::null_mut()),
        };
        return counter;
    }

    unsafe fn print_slot(&self, index: usize) {
        let slot = &self.slots[index];
        let key = slot.key.load(Ordering::Relaxed);
        println!("slot {}: {:?}", index, slot);
        if key.is_null() {
            println!("\t key=null")
        }
        else {
            println!("\t key={:?}", *key);
        }
    }

    unsafe fn unsafe_get(&self, key: HashKey) -> usize {
        let size = self.size;
        let mut index = djb2_hash(&key) % size;
        let raw_key = Box::into_raw(key);
        loop {
            let slot = &self.slots[index];
            let other_key = slot.key.load(Ordering::Relaxed);
            if other_key.is_null() {
                return 0;
            }
            else if *other_key == *raw_key{
                return slot.count.load(Ordering::Relaxed);
            }
            index = (index + 1) % size;
        }
    }

    unsafe fn unsafe_incr(&mut self, mut key: HashKey, count: usize) -> usize {
        let size = self.size;
        let mut index = djb2_hash(&key) % size;
        let raw_key = Box::into_raw(key);
        loop {
            let slot = &self.slots[index];
            let other_key = slot.key.load(Ordering::Relaxed);
            if other_key.is_null() {
                let res = slot.key.compare_exchange(other_key,
                                                    raw_key,
                                                    Ordering::Relaxed,
                                                    Ordering::Relaxed);
                let status = match res {
                    Ok(v) => v.is_null() || *v == *raw_key,
                    Err(v) => v.is_null() || *v == *raw_key,
                };
                if status {
                    self.used.fetch_add(1, Ordering::Relaxed);
                    //TODO(rossdylan) handle resizing
                    let added = slot.count.fetch_add(count, Ordering::Relaxed);
                    return added
                }
            }
            else if *other_key == *raw_key {
                return slot.count.fetch_add(count, Ordering::Relaxed);
            }
            index = (index + 1) % size
        }
    }

    pub fn incr(&mut self, key: &str, count: usize) -> usize {
        return unsafe { self.unsafe_incr(clean_key(key), count) };
    }

    pub fn get(&self, key: &str) -> usize {
        return unsafe { self.unsafe_get(clean_key(key)) };
    }
}

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

    #[test]
    fn increment() {
        let mut counter = Counter::new();
        let res = counter.incr("foo", 1);
        assert_eq!(res, 0);
    }

    #[test]
    fn get() {
        let mut counter = Counter::new();
        let res = counter.incr("foo", 1);
        let count = counter.get("foo");
        assert_eq!(count, 1);
    }

    #[bench]
    fn bench_incr(b: &mut Bencher) {
        let mut counter = Counter::new();
        b.iter(|| counter.incr("foo", 1))
    }

    #[bench]
    fn bench_get(b: &mut Bencher) {
        let mut counter = Counter::new();
        counter.incr("foo", 100);
        b.iter(|| counter.get("foo"))
    }
}
<|endoftext|>


<commit_before>//! [(Link to repository page.)](https://github.com/C4K3/Ozelot)
//!
//! This is a library made for interacting with the Minecraft protocl
//! (MCMODERN only, not MCPE.)
//!
//! It is mostly a low-level library, its goals are to
//! handle everything network related, but nothing beyond that. For example
//! this library does not support any types beyond ones found in standard Rust,
//! this results in certain packets that contain compound datatypes not having
//! their complex fields serialized by this library, but instead handing the
//! raw binary data to consumers of this library to parse however they wish.
//! One example of this is packets that contain NBT data, the packets are read
//! but the NBT data is not in any way parsed by this library.
//!
//! This library currently only supports the client side of the connection,
//! but servers may be supported in the future as well, since we already have
//! all the packet definitions.
//!
//! Currently the library is entirely synchronous, requiring consumers to handle
//! concurrency however they wish. It would be cool to add an asynchronous API
//! though, maybe using mio.
//!
//! The library nominally supports every packet used in MCMODERN, but the goal
//! is still to add lots more helper functions and other useful things.
//!
//! The library does not yet have any stable releases, not because it may
//! contain bugs (which it certainly does,) but because the API may be
//! significantly restructured without warning.
//!
//! # Examples
//!
//! Connecting to a remote server as an authenticated user, printing all chat
//! messages, and then echoing back messages that appear not to be written by us
//! (else we'd get into an infinite loop echoing our own messages.)
//!
//! ```rust,no_run
//! use ozelot::{mojang, Client, serverbound, utils};
//! use ozelot::clientbound::ClientboundPacket;
//!
//! let auth = mojang::Authenticate::new("my_email@example.com".to_string(),
//!                                      "my_password".to_string())
//!     .perform().unwrap();
//!
//!
//! /* By using connect_authenticated, auto_handle will be true and thus ozelot
//!  * will respond to keepalives automatically */
//! let mut client = Client::connect_authenticated("minecraft.example.com",
//!                                                25565, &auth).unwrap();
//!
//! let username = auth.selectedProfile.name;
//!
//! 'main: loop {
//!     let packets = client.read().unwrap();
//!     for packet in packets {
//!         match packet {
//!         ClientboundPacket::PlayDisconnect(ref p) => {
//!             println!("Disconnected, reason: {}",
//!                      utils::chat_to_str(p.get_reason()));
//!             break 'main;
//!         },
//!         ClientboundPacket::ChatMessage(ref p) => {
//!             let msg = utils::chat_to_str(p.get_chat());
//!             println!("{}", msg);
//!             if !msg.contains(&username) {
//!                 /* Since we don't want an infinite loop, we don't echo back
//!                  * our own messages. We say that a received message wasn't
//!                  * written by us if it doesn't contain our username
//!                  *
//!                  * Note that this echoes back the raw chat message, that is
//!                  * playername and everything, and also non-chat messages. */
//!                 let response = serverbound::ChatMessage::new(msg);
//!                 client.send(response).unwrap();
//!             }
//!         },
//!         /* We throw away all other packets */
//!         _ => (),
//!         }
//!     }
//! }
//! ```
extern crate byteorder;
extern crate flate2;
extern crate netbuf;
extern crate openssl;
extern crate reqwest; /* Holy fuck the dependencies needed just to make 2
                         HTTP POST requests ... */
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate derive_new;

#[macro_use]
mod macros;
mod client;
mod connection;
#[allow(non_snake_case)]
mod json;
mod server;
mod yggdrasil;
pub mod clientbound;
#[allow(non_snake_case)]
pub mod mojang;
pub mod read;
pub mod serverbound;
pub mod utils;
pub mod write;
#[cfg(test)]
mod tests;

pub use client::Client;
pub use server::Server;

use std::fmt;

use flate2::Compression;

const COMPRESSION_LEVEL: Compression = Compression::Default;
/// The protocol version supported by this version of ozelot
pub const PROTOCOL_VERSION: i32 = 316;

/// FIXME temporary struct until u128 lands in stable rust, used for uuids
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[allow(non_camel_case_types)]
pub struct u128(pub u64, pub u64);

/// This tracks which state of play the client is in. The value of this changes
/// the meaning of the different packet ids.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClientState {
    Handshake,
    Status,
    Login,
    Play,
}
impl fmt::Display for ClientState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match self {
                   &ClientState::Handshake => "Handshake",
                   &ClientState::Status => "Status",
                   &ClientState::Login => "Login",
                   &ClientState::Play => "Play",
               })
    }
}
<commit_msg>Update documentation<commit_after>//! [(Link to repository page.)](https://github.com/C4K3/Ozelot)
//!
//! This is a library made for interacting with the Minecraft protocl
//! (MCMODERN only, not MCPE.)
//!
//! It is mostly a low-level library, its goals are to
//! handle everything network related, but nothing beyond that. For example
//! this library does not support any types beyond ones found in standard Rust,
//! this results in certain packets that contain compound datatypes not having
//! their complex fields serialized by this library, but instead handing the
//! raw binary data to consumers of this library to parse however they wish.
//! One example of this is packets that contain NBT data, the packets are read
//! but the NBT data is not in any way parsed by this library. You'll probably
//! want to see what the meanings of each of the packets are, which is
//! documented on [wiki.vg](http://wiki.vg/Main_Page). The [protocol
//! documentation](http://wiki.vg/Protocol) in particular is likely to be a
//! necessary companion to using this library.
//!
//! Currently the library is entirely synchronous, requiring consumers to handle
//! concurrency however they wish. It would be cool to add an asynchronous API
//! though, maybe using mio.
//!
//! The library nominally supports every packet used in MCMODERN, but the goal
//! is still to add lots more helper functions and other useful things. There
//! are still many errors and inconvenient things in the library, where changes
//! or helper functions would be good to add. If you find any errors or
//! suggestions for improvement, no matter how trivial, then post it on the
//! bugtracker.
//!
//! The library does not yet have any stable releases, not because it may
//! contain bugs (which it certainly does,) but because the API may be
//! significantly restructured without warning.
//!
//! # Examples
//!
//! Connecting to a remote server as an authenticated user, printing all chat
//! messages, and then echoing back messages that appear not to be written by us
//! (else we'd get into an infinite loop echoing our own messages.)
//!
//! ```rust,no_run
//! use ozelot::{mojang, Client, serverbound, utils};
//! use ozelot::clientbound::ClientboundPacket;
//!
//! let auth = mojang::Authenticate::new("my_email@example.com".to_string(),
//!                                      "my_password".to_string())
//!     .perform().unwrap();
//!
//!
//! /* By using connect_authenticated, auto_handle will be true and thus ozelot
//!  * will respond to keepalives automatically */
//! let mut client = Client::connect_authenticated("minecraft.example.com",
//!                                                25565, &auth).unwrap();
//!
//! let username = auth.selectedProfile.name;
//!
//! 'main: loop {
//!     let packets = client.read().unwrap();
//!     for packet in packets {
//!         match packet {
//!         ClientboundPacket::PlayDisconnect(ref p) => {
//!             println!("Disconnected, reason: {}",
//!                      utils::chat_to_str(p.get_reason()));
//!             break 'main;
//!         },
//!         ClientboundPacket::ChatMessage(ref p) => {
//!             let msg = utils::chat_to_str(p.get_chat());
//!             println!("{}", msg);
//!             if !msg.contains(&username) {
//!                 /* Since we don't want an infinite loop, we don't echo back
//!                  * our own messages. We say that a received message wasn't
//!                  * written by us if it doesn't contain our username
//!                  *
//!                  * Note that this echoes back the raw chat message, that is
//!                  * playername and everything, and also non-chat messages. */
//!                 let response = serverbound::ChatMessage::new(msg);
//!                 client.send(response).unwrap();
//!             }
//!         },
//!         /* We throw away all other packets */
//!         _ => (),
//!         }
//!     }
//! }
//! ```
extern crate byteorder;
extern crate flate2;
extern crate netbuf;
extern crate openssl;
extern crate reqwest; /* Holy fuck the dependencies needed just to make 2
                         HTTP POST requests ... */
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate derive_new;

#[macro_use]
mod macros;
mod client;
mod connection;
#[allow(non_snake_case)]
mod json;
mod server;
mod yggdrasil;
pub mod clientbound;
#[allow(non_snake_case)]
pub mod mojang;
pub mod read;
pub mod serverbound;
pub mod utils;
pub mod write;
#[cfg(test)]
mod tests;

pub use client::Client;
pub use server::Server;

use std::fmt;

use flate2::Compression;

const COMPRESSION_LEVEL: Compression = Compression::Default;
/// The protocol version supported by this version of ozelot
pub const PROTOCOL_VERSION: i32 = 316;

/// FIXME temporary struct until u128 lands in stable rust, used for uuids
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[allow(non_camel_case_types)]
pub struct u128(pub u64, pub u64);

/// This tracks which state of play the client is in. The value of this changes
/// the meaning of the different packet ids.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClientState {
    Handshake,
    Status,
    Login,
    Play,
}
impl fmt::Display for ClientState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match self {
                   &ClientState::Handshake => "Handshake",
                   &ClientState::Status => "Status",
                   &ClientState::Login => "Login",
                   &ClientState::Play => "Play",
               })
    }
}
<|endoftext|>