<commit_before>//! Support for Unix domain socket clients and servers.
#![feature(io, std_misc, path, core)]
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/rust-unix-socket/doc")]

extern crate libc;

use std::cmp;
use std::ffi::AsOsStr;
use std::io;
use std::iter::IntoIterator;
use std::mem;
use std::num::Int;
use std::os::unix::{Fd, OsStrExt, AsRawFd};
use std::path::AsPath;

struct Inner(Fd);

impl Drop for Inner {
    fn drop(&mut self) {
        unsafe {
            libc::close(self.0);
        }
    }
}

impl Inner {
    unsafe fn new() -> io::Result<Inner> {
        let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
        if fd < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(Inner(fd))
        }
    }

}

unsafe fn sockaddr_un<P: AsPath + ?Sized>(path: &P) -> io::Result<libc::sockaddr_un> {
    let mut addr: libc::sockaddr_un = mem::zeroed();
    addr.sun_family = libc::AF_UNIX as libc::sa_family_t;

    let bytes = path.as_path().as_os_str().as_bytes();
    if bytes.len() >= addr.sun_path.len() {
        return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                  "path must be smaller than SUN_LEN",
                                  None));
    }
    for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
        *dst = *src as libc::c_char;
    }
    // null byte's already there because we zeroed the struct

    Ok(addr)
}

/// A stream which communicates over a Unix domain socket.
pub struct UnixStream {
    inner: Inner,
}

impl UnixStream {
    /// Connect to the socket named by `path`.
    pub fn connect<P: AsPath + ?Sized>(path: &P) -> io::Result<UnixStream> {
        unsafe {
            let inner = try!(Inner::new());
            let addr = try!(sockaddr_un(path));

            let ret = libc::connect(inner.0,
                                    &addr as *const _ as *const _,
                                    mem::size_of::<libc::sockaddr_un>() as libc::socklen_t);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixStream {
                    inner: inner,
                })
            }
        }
    }
}

fn calc_len(buf: &[u8]) -> libc::size_t {
    cmp::min(<libc::size_t as Int>::max_value() as usize, buf.len()) as libc::size_t
}

impl io::Read for UnixStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = unsafe {
            libc::recv(self.inner.0, buf.as_mut_ptr() as *mut _, calc_len(buf), 0)
        };

        if ret < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }
}

impl io::Write for UnixStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let ret = unsafe {
            libc::send(self.inner.0, buf.as_ptr() as *const _, calc_len(buf), 0)
        };

        if ret < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsRawFd for UnixStream {
    fn as_raw_fd(&self) -> Fd {
        self.inner.0
    }
}

/// A structure representing a Unix domain socket server.
pub struct UnixListener {
    inner: Inner,
}

impl UnixListener {
    /// Creates a new `UnixListener` which will be bound to the specified socket.
    pub fn bind<P: AsPath + ?Sized>(path: &P) -> io::Result<UnixListener> {
        unsafe {
            let inner = try!(Inner::new());
            let addr = try!(sockaddr_un(path));

            let ret = libc::bind(inner.0,
                                 &addr as *const _ as *const _,
                                 mem::size_of::<libc::sockaddr_un>() as libc::socklen_t);
            if ret < 0 {
                return Err(io::Error::last_os_error());
            }

            let ret = libc::listen(inner.0, 128);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixListener {
                    inner: inner,
                })
            }
        }
    }

    /// Accepts a new incoming connection to this listener.
    pub fn accept(&self) -> io::Result<UnixStream> {
        unsafe {
            let ret = libc::accept(self.inner.0, 0 as *mut _, 0 as *mut _);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixStream {
                    inner: Inner(ret)
                })
            }
        }
    }

    /// Returns an iterator over incoming connections.
    ///
    /// The iterator will never return `None`.
    pub fn incoming<'a>(&'a self) -> Incoming<'a> {
        Incoming {
            listener: self
        }
    }
}

impl AsRawFd for UnixListener {
    fn as_raw_fd(&self) -> Fd {
        self.inner.0
    }
}

impl<'a> IntoIterator for &'a UnixListener {
    type Item = io::Result<UnixStream>;
    type IntoIter = Incoming<'a>;

    fn into_iter(self) -> Incoming<'a> {
        self.incoming()
    }
}

/// An iterator over incoming connections to a `UnixListener`.
///
/// It will never return `None`.
pub struct Incoming<'a> {
    listener: &'a UnixListener,
}

impl<'a> Iterator for Incoming<'a> {
    type Item = io::Result<UnixStream>;

    fn next(&mut self) -> Option<io::Result<UnixStream>> {
        Some(self.listener.accept())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (Int::max_value(), None)
    }
}

#[cfg(test)]
mod test {
    extern crate temporary;

    use std::thread;
    use std::io;
    use std::io::prelude::*;

    use {UnixListener, UnixStream};

    macro_rules! or_panic {
        ($e:expr) => {
            match $e {
                Ok(e) => e,
                Err(e) => panic!("{}", e),
            }
        }
    }

    #[test]
    fn basic() {
        let dir = or_panic!(temporary::Directory::new("unix_socket"));
        let socket_path = dir.path().join("sock");
        let msg1 = b"hello";
        let msg2 = b"world!";

        let listener = or_panic!(UnixListener::bind(&socket_path));
        let thread = thread::scoped(|| {
            let mut stream = or_panic!(listener.accept());
            let mut buf = [0; 5];
            or_panic!(stream.read(&mut buf));
            assert_eq!(msg1, buf);
            or_panic!(stream.write_all(msg2));
        });

        let mut stream = or_panic!(UnixStream::connect(&socket_path));
        or_panic!(stream.write_all(msg1));
        let mut buf = vec![];
        or_panic!(stream.read_to_end(&mut buf));
        assert_eq!(msg2, buf);
        drop(stream);

        thread.join();
    }

    #[test]
    fn iter() {
        let dir = or_panic!(temporary::Directory::new("unix_socket"));
        let socket_path = dir.path().join("sock");

        let listener = or_panic!(UnixListener::bind(&socket_path));
        let thread = thread::scoped(|| {
            for stream in listener.incoming().take(2) {
                let mut stream = or_panic!(stream);
                let mut buf = [0];
                or_panic!(stream.read(&mut buf));
            }
        });

        for _ in 0..2 {
            let mut stream = or_panic!(UnixStream::connect(&socket_path));
            or_panic!(stream.write_all(&[0]));
        }

        thread.join();
    }

    #[test]
    fn long_path() {
        let socket_path = "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd\
                           asdfasdfasdfadfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd";
        match UnixStream::connect(socket_path) {
            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
            Err(e) => panic!("unexpected error {}", e),
            Ok(_) => panic!("unexpected success"),
        }

        match UnixListener::bind(socket_path) {
            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
            Err(e) => panic!("unexpected error {}", e),
            Ok(_) => panic!("unexpected success"),
        }
    }
}
<commit_msg>Add support for socketpair(2)<commit_after>//! Support for Unix domain socket clients and servers.
#![feature(io, std_misc, path, core)]
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/rust-unix-socket/doc")]

extern crate libc;

use std::cmp;
use std::ffi::AsOsStr;
use std::io;
use std::iter::IntoIterator;
use std::mem;
use std::num::Int;
use std::os::unix::{Fd, OsStrExt, AsRawFd};
use std::path::AsPath;
use libc::c_int;

extern "C" {
    fn socketpair(domain: c_int, ty: c_int, proto: c_int, sv: *mut [c_int; 2]) -> c_int;
}

struct Inner(Fd);

impl Drop for Inner {
    fn drop(&mut self) {
        unsafe {
            libc::close(self.0);
        }
    }
}

impl Inner {
    unsafe fn new() -> io::Result<Inner> {
        let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
        if fd < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(Inner(fd))
        }
    }

    unsafe fn new_pair() -> io::Result<[Inner; 2]> {
        let mut fds = [0, 0];
        let res = socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, &mut fds);
        if res < 0 {
            return Err(io::Error::last_os_error());
        }
        debug_assert_eq!(res, 0);
        Ok([Inner(fds[0]), Inner(fds[1])])
    }
}

unsafe fn sockaddr_un<P: AsPath + ?Sized>(path: &P) -> io::Result<libc::sockaddr_un> {
    let mut addr: libc::sockaddr_un = mem::zeroed();
    addr.sun_family = libc::AF_UNIX as libc::sa_family_t;

    let bytes = path.as_path().as_os_str().as_bytes();
    if bytes.len() >= addr.sun_path.len() {
        return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                  "path must be smaller than SUN_LEN",
                                  None));
    }
    for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
        *dst = *src as libc::c_char;
    }
    // null byte's already there because we zeroed the struct

    Ok(addr)
}

/// A stream which communicates over a Unix domain socket.
pub struct UnixStream {
    inner: Inner,
}

impl UnixStream {
    /// Connect to the socket named by `path`.
    pub fn connect<P: AsPath + ?Sized>(path: &P) -> io::Result<UnixStream> {
        unsafe {
            let inner = try!(Inner::new());
            let addr = try!(sockaddr_un(path));

            let ret = libc::connect(inner.0,
                                    &addr as *const _ as *const _,
                                    mem::size_of::<libc::sockaddr_un>() as libc::socklen_t);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixStream {
                    inner: inner,
                })
            }
        }
    }

    /// Create an unnamed pair of connected sockets.
    ///
    /// Returns two `UnixStream`s which are connected to each other.
    pub fn unnamed() -> io::Result<[UnixStream; 2]> {
        unsafe {
            let [i1, i2] = try!(Inner::new_pair());
            Ok([UnixStream { inner: i1 }, UnixStream { inner: i2 }])
        }
    }
}

fn calc_len(buf: &[u8]) -> libc::size_t {
    cmp::min(<libc::size_t as Int>::max_value() as usize, buf.len()) as libc::size_t
}

impl io::Read for UnixStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = unsafe {
            libc::recv(self.inner.0, buf.as_mut_ptr() as *mut _, calc_len(buf), 0)
        };

        if ret < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }
}

impl io::Write for UnixStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let ret = unsafe {
            libc::send(self.inner.0, buf.as_ptr() as *const _, calc_len(buf), 0)
        };

        if ret < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as usize)
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsRawFd for UnixStream {
    fn as_raw_fd(&self) -> Fd {
        self.inner.0
    }
}

/// A structure representing a Unix domain socket server.
pub struct UnixListener {
    inner: Inner,
}

impl UnixListener {
    /// Creates a new `UnixListener` which will be bound to the specified socket.
    pub fn bind<P: AsPath + ?Sized>(path: &P) -> io::Result<UnixListener> {
        unsafe {
            let inner = try!(Inner::new());
            let addr = try!(sockaddr_un(path));

            let ret = libc::bind(inner.0,
                                 &addr as *const _ as *const _,
                                 mem::size_of::<libc::sockaddr_un>() as libc::socklen_t);
            if ret < 0 {
                return Err(io::Error::last_os_error());
            }

            let ret = libc::listen(inner.0, 128);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixListener {
                    inner: inner,
                })
            }
        }
    }

    /// Accepts a new incoming connection to this listener.
    pub fn accept(&self) -> io::Result<UnixStream> {
        unsafe {
            let ret = libc::accept(self.inner.0, 0 as *mut _, 0 as *mut _);
            if ret < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(UnixStream {
                    inner: Inner(ret)
                })
            }
        }
    }

    /// Returns an iterator over incoming connections.
    ///
    /// The iterator will never return `None`.
    pub fn incoming<'a>(&'a self) -> Incoming<'a> {
        Incoming {
            listener: self
        }
    }
}

impl AsRawFd for UnixListener {
    fn as_raw_fd(&self) -> Fd {
        self.inner.0
    }
}

impl<'a> IntoIterator for &'a UnixListener {
    type Item = io::Result<UnixStream>;
    type IntoIter = Incoming<'a>;

    fn into_iter(self) -> Incoming<'a> {
        self.incoming()
    }
}

/// An iterator over incoming connections to a `UnixListener`.
///
/// It will never return `None`.
pub struct Incoming<'a> {
    listener: &'a UnixListener,
}

impl<'a> Iterator for Incoming<'a> {
    type Item = io::Result<UnixStream>;

    fn next(&mut self) -> Option<io::Result<UnixStream>> {
        Some(self.listener.accept())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (Int::max_value(), None)
    }
}

#[cfg(test)]
mod test {
    extern crate temporary;

    use std::thread;
    use std::io;
    use std::io::prelude::*;

    use {UnixListener, UnixStream};

    macro_rules! or_panic {
        ($e:expr) => {
            match $e {
                Ok(e) => e,
                Err(e) => panic!("{}", e),
            }
        }
    }

    #[test]
    fn basic() {
        let dir = or_panic!(temporary::Directory::new("unix_socket"));
        let socket_path = dir.path().join("sock");
        let msg1 = b"hello";
        let msg2 = b"world!";

        let listener = or_panic!(UnixListener::bind(&socket_path));
        let thread = thread::scoped(|| {
            let mut stream = or_panic!(listener.accept());
            let mut buf = [0; 5];
            or_panic!(stream.read(&mut buf));
            assert_eq!(msg1, buf);
            or_panic!(stream.write_all(msg2));
        });

        let mut stream = or_panic!(UnixStream::connect(&socket_path));
        or_panic!(stream.write_all(msg1));
        let mut buf = vec![];
        or_panic!(stream.read_to_end(&mut buf));
        assert_eq!(msg2, buf);
        drop(stream);

        thread.join();
    }

    #[test]
    fn unnamed() {
        let msg1 = b"hello";
        let msg2 = b"world!";

        let [mut s1, mut s2] = or_panic!(UnixStream::unnamed());
        let thread = thread::scoped(move || {
            // s1 must be moved in or the test will hang!
            let mut buf = [0; 5];
            or_panic!(s1.read(&mut buf));
            assert_eq!(msg1, buf);
            or_panic!(s1.write_all(msg2));
        });

        or_panic!(s2.write_all(msg1));
        let mut buf = vec![];
        or_panic!(s2.read_to_end(&mut buf));
        assert_eq!(msg2, buf);
        drop(s2);

        thread.join();
    }

    #[test]
    fn iter() {
        let dir = or_panic!(temporary::Directory::new("unix_socket"));
        let socket_path = dir.path().join("sock");

        let listener = or_panic!(UnixListener::bind(&socket_path));
        let thread = thread::scoped(|| {
            for stream in listener.incoming().take(2) {
                let mut stream = or_panic!(stream);
                let mut buf = [0];
                or_panic!(stream.read(&mut buf));
            }
        });

        for _ in 0..2 {
            let mut stream = or_panic!(UnixStream::connect(&socket_path));
            or_panic!(stream.write_all(&[0]));
        }

        thread.join();
    }

    #[test]
    fn long_path() {
        let socket_path = "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd\
                           asdfasdfasdfadfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd";
        match UnixStream::connect(socket_path) {
            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
            Err(e) => panic!("unexpected error {}", e),
            Ok(_) => panic!("unexpected success"),
        }

        match UnixListener::bind(socket_path) {
            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
            Err(e) => panic!("unexpected error {}", e),
            Ok(_) => panic!("unexpected success"),
        }
    }
}
<|endoftext|>


<commit_before>//
// yaml.rs
// Nothing to see here yet
//

#![crate_id="yaml"]

use std::iter::Iterator;
use std::option::Option;
use std::io::{IoResult, MemReader};
use std::borrow::Cow;
use self::Token::*;

/// A Yaml Tokenizer
///
/// A tokenizer takes a byte stream and produces a stream of Tokens
/// This shelters the parser from the complexity of dealing with raw bytes.
///
pub struct Tokenizer<'a> {
    reader: Box<Reader + 'a>,
    stack: Vec<u8>,
}

impl <'a>Tokenizer<'a> {

    /// Creates a new Tokenizer from a Reader
    pub fn new<T: Reader + 'a>(reader: Box<T>) -> Tokenizer<'a> {
        Tokenizer {
            reader: reader,
            stack: Vec::new(),
        }
    }

    fn read_char(&mut self) -> Option<char> {
        match self.reader.read_byte() {
            Ok(byte) => Some(byte as char),
            Err(_) => None,
        }
    }

    pub fn pop(&mut self) -> Option<char> {
        if(self.stack.len() == 0) {
            self.read_char()
        } else {
            match self.stack.pop() {
                Some(byte) => Some(byte as char),
                None => None,
            }
        }
    }

    pub fn next_token(&mut self) -> Option<Token> {
        match self.pop() {
            Some(character) => match character {
                // TODO: factor out Some(Token)
                '[' => Some(SequenceStart),
                ']' => Some(SequenceEnd),
                '{' => Some(MappingStart),
                '}' => Some(MappingEnd),
                '-' => {
                    if self.consume("--") {
                        Some(DocumentStart)
                    } else {
                        Some(SequenceEntry)
                    }
                },
                ':' => Some(MappingSeparator),
                ',' => Some(CollectionSeparator),
                '?' => Some(ComplexKey),
                '!' => Some(Tag),
                '&' => {
                    match self.consume_anchor() {
                        Some(string) => Some(Anchor(string)),
                        None => None,
                    }
                },
                '*' => {
                    match self.consume_anchor() {
                        Some(string) => Some(Alias(string)),
                        None => None,
                    }
                },
                '#' => {
                    self.throw_away_comment();
                    self.next_token()
                },
                '\'' => Some(SingleQuote),
                '"' => Some(DoubleQuote),
                '|' => Some(Literal),
                '>' => Some(Folded),
                '.' => {
                    if self.consume("..") {
                        Some(DocumentEnd)
                    } else {
                        self.stack.push(character as u8);
                        self.consume_scalar()
                    }
                }
                _ => {
                    self.stack.push(character as u8);
                    self.consume_scalar()
                },
            },
            None => None,
        }
    }

    fn throw_away_comment(&mut self) {
        loop {
            match self.pop() {
                Some(character) => match character {
                    '\n' => { break },
                    _ => { continue },
                },
                None => {
                    break;
                }
            }
        }
    }

    fn consume_anchor(&mut self) -> Option<String> {
        let mut eaten = Vec::new();
        loop {
            match self.pop() {
                Some(character) => match character {
                    'A'...'Z'|'a'...'z'|'0'...'9'|'-'|'_' => {
                        eaten.push(character as u8);
                    },
                    _ => {
                        self.stack.push(character as u8);
                        break;
                    },
                },
                None => {
                    break;
                }
            }
        }

        match String::from_utf8(eaten) {
            Ok(string) => Some(string),
            Err(_) => None,
        }

    }

    fn consume_scalar(&mut self) -> Option<Token> {
        let mut eaten = Vec::new();
        loop {
            match self.pop() {
                Some(character) => match character {
                    'A'...'Z'|'a'...'z'|'0'...'9' => {
                        eaten.push(character as u8);
                    },
                    _ => {
                        self.stack.push(character as u8);
                        break;
                    },
                },
                None => {
                    break;
                }
            }
        }

        match String::from_utf8(eaten) {
            Ok(string) => Some(Scalar(string)),
            Err(_) => None,
        }
    }

    fn consume(&mut self, edible: &'static str) -> bool {
        let mut eaten = Vec::new();
        for expected in edible.chars() {
            let character = self.pop();
            if character.is_some() {
                let c = character.unwrap();
                eaten.push(c as u8);
                if c == expected {
                    continue;
                }
            }
            for ate in eaten.drain().rev() {
                self.stack.push(ate);
            }
            return false;
        }
        true
    }
}

/// All the types of tokens
///
/// Describes all of the token types described by the [Yaml 1.0 Spec](http://yaml.org/spec/1.0/)
///
#[derive(PartialEq, Debug)]
pub enum Token {

    /// `[`: the start of a _flow_ sequence
    /// `c-sequence-start` in the spec
    SequenceStart,

    /// `]`: the end of a _flow_ sequence
    /// `c-sequence-end` in the spec
    SequenceEnd,

    /// `{`: the end of a _flow_ mapping
    /// `c-mapping-start` in the spec
    MappingStart,

    /// `}`: the end of a _flow_ mapping
    /// `c-mapping-end` in the spec
    MappingEnd,

    /// `-`: indicates an entry in a sequence
    /// `c-sequence-entry` in the spec
    SequenceEntry,

    /// `:`: separates key from value in a mapping
    /// `c-mapping-entry` in the spec
    MappingSeparator,

    /// `,`: separates entries in _flow_ collections (mapping or sequence)
    /// `c-collect-entry` in the spec
    CollectionSeparator,

    /// `?`: indicates a complex key (e.g a non-scalar key)
    /// `c-complex-key` in the spec
    ComplexKey,

    /// `!`: indicates a tag property
    /// `c-tag` in the spec
    Tag,

    /// `&`: indicates an anchor property (e.g setting a variable)
    /// `c-anchor` in the spec
    Anchor(String),

    /// `*`: indicates an anchor property (e.g using a variable)
    /// `c-alias` in the spec
    Alias(String),

    /// `|`: indicates a literal value (not to be escaped)
    /// `c-literal` in the spec
    Literal,

    /// `>`: indicates a folded value (ignore line breaks)
    /// `c-folded` in the spec
    Folded,

    /// `'`: a single quoted scalar
    /// `c-single-quote` in the spec
    SingleQuote,

    /// `"`: a double quoted scalar
    /// `c-double-quote` in the spec
    DoubleQuote,

    /// `#`: a comment
    /// `c-throwaway`
    Comment,

    /// `%`: a directive (tags for the YAML parser)
    /// `c-directive` in the spec
    Directive,

    /// `@ | \``: reserved for future use?
    /// `c-reserved` in the spec
    Reserved,

    ///TODO Documentation
    ///
    DocumentStart,

    ///TODO: Documentation
    ///
    DocumentEnd,

    /// ``: a line break with no specific purpose
    LineBreakGeneric,

    /// ``
    LineBreak(LineBreakType),

    Other, // A temporary addition for unimplemented tokens
    Scalar(String),
    Eof,
}

#[derive(PartialEq, Copy, Debug)]
pub enum LineBreakType {
    Generic,
    LineSeparator,
    ParagraphSeparator
}

impl <'a>Iterator for Tokenizer<'a> {

    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.next_token()
    }
}

mod test {

    use std::io::MemReader;
    use super::{Tokenizer, Token};
    use super::Token::*;

    #[test]
    fn test_tokens() {
        let stream = "--hallo";
        let mut reader = MemReader::new(stream.bytes().collect());
        let mut tokenizer = Tokenizer::new(Box::new(reader));
        let tokens: Vec<Token> = tokenizer.collect();
        assert!(tokens == vec![SequenceEntry, SequenceEntry, Scalar("hallo".to_string())]);
    }
}
<commit_msg>tokenize yaml directives<commit_after>//
// yaml.rs
// Nothing to see here yet
//

#![crate_id="yaml"]

use std::iter::Iterator;
use std::option::Option;
use std::io::{IoResult, MemReader};
use std::borrow::Cow;
use self::Token::*;

/// A Yaml Tokenizer
///
/// A tokenizer takes a byte stream and produces a stream of Tokens
/// This shelters the parser from the complexity of dealing with raw bytes.
///
pub struct Tokenizer<'a> {
    reader: Box<Reader + 'a>,
    stack: Vec<u8>,
}

impl <'a>Tokenizer<'a> {

    /// Creates a new Tokenizer from a Reader
    pub fn new<T: Reader + 'a>(reader: Box<T>) -> Tokenizer<'a> {
        Tokenizer {
            reader: reader,
            stack: Vec::new(),
        }
    }

    fn read_char(&mut self) -> Option<char> {
        match self.reader.read_byte() {
            Ok(byte) => Some(byte as char),
            Err(_) => None,
        }
    }

    pub fn pop(&mut self) -> Option<char> {
        if(self.stack.len() == 0) {
            self.read_char()
        } else {
            match self.stack.pop() {
                Some(byte) => Some(byte as char),
                None => None,
            }
        }
    }

    pub fn next_token(&mut self) -> Option<Token> {
        match self.pop() {
            Some(character) => match character {
                // TODO: factor out Some(Token)
                '[' => Some(SequenceStart),
                ']' => Some(SequenceEnd),
                '{' => Some(MappingStart),
                '}' => Some(MappingEnd),
                '-' => {
                    if self.consume("--") {
                        Some(DocumentStart)
                    } else {
                        Some(SequenceEntry)
                    }
                },
                ':' => Some(MappingSeparator),
                ',' => Some(CollectionSeparator),
                '?' => Some(ComplexKey),
                '!' => Some(Tag),
                '&' => {
                    match self.consume_anchor() {
                        Some(string) => Some(Anchor(string)),
                        None => None,
                    }
                },
                '*' => {
                    match self.consume_anchor() {
                        Some(string) => Some(Alias(string)),
                        None => None,
                    }
                },
                '#' => {
                    self.throw_away_comment();
                    self.next_token()
                },
                '\'' => Some(SingleQuote),
                '"' => Some(DoubleQuote),
                '|' => Some(Literal),
                '>' => Some(Folded),
                '.' => {
                    if self.consume("..") {
                        Some(DocumentEnd)
                    } else {
                        self.stack.push(character as u8);
                        self.consume_scalar()
                    }
                },
                '%' => self.consume_directive(),
                // TODO: do more with whitespace than just
                // throw it out!
                '\n' | ' ' | '\t' => {
                    self.throw_away_whitespace();
                    self.next_token()
                }
                _ => {
                    self.stack.push(character as u8);
                    self.consume_scalar()
                },
            },
            None => None,
        }
    }

    fn throw_away_whitespace(&mut self) {
        loop {
            match self.pop() {
                Some(character) => match character {
                    '\n' | ' ' | '\t' => { continue },
                    _ => {
                        //TODO: factor out "as u8" on the push
                        self.stack.push(character as u8);
                        break;
                    },
                },
                None => {
                    break;
                }
            }
        }

    }

    fn throw_away_comment(&mut self) {
        loop {
            match self.pop() {
                Some(character) => match character {
                    '\n' => { break },
                    _ => { continue },
                },
                None => {
                    break;
                }
            }
        }
    }

    fn consume_directive(&mut self) -> Option<Token> {
        if self.consume("YAML ") {
            match self.consume_yaml_version() {
                Some(version) => Some(YamlDirective(version)),
                None => None,
            }

        // TODO: Other types of directives
        } else {
            None
        }
    }

    fn consume_yaml_version(&mut self) -> Option<YamlVersion> {
        let major = match self.consume_number() {
            Some(number) => number,
            None => { return None },
        };
        if !self.consume(".") {
            return None;
        }
        let minor = match self.consume_number() {
            Some(number) => number,
            None => { return None },
        };
        Some(YamlVersion {major: major, minor: minor})
    }

    fn consume_number(&mut self) -> Option<usize> {
        let mut accumulator: Option<usize> = None;
        loop {
            match self.pop() {
                Some(character) => match character {
                    '0' ... '9' => {
                        let digit: usize = character as usize - '0' as usize;
                        match accumulator {
                            Some(mut a) => {
                                a *= 10;
                                a += digit;
                            }
                            None => {
                                accumulator = Some(digit);
                            }
                        }
                    },
                    _ => {
                        self.stack.push(character as u8);
                        break;
                    }
                },
                None => { return None },
            }
        }
        accumulator
    }

    fn consume_anchor(&mut self) -> Option<String> {
        let mut eaten = Vec::new();
        loop {
            match self.pop() {
                Some(character) => match character {
                    'A'...'Z'|'a'...'z'|'0'...'9'|'-'|'_' => {
                        eaten.push(character as u8);
                    },
                    _ => {
                        self.stack.push(character as u8);
                        break;
                    },
                },
                None => {
                    break;
                }
            }
        }

        match String::from_utf8(eaten) {
            Ok(string) => Some(string),
            Err(_) => None,
        }

    }

    fn consume_scalar(&mut self) -> Option<Token> {
        let mut eaten = Vec::new();
        loop {
            match self.pop() {
                Some(character) => match character {
                    'A'...'Z'|'a'...'z'|'0'...'9' => {
                        eaten.push(character as u8);
                    },
                    _ => {
                        self.stack.push(character as u8);
                        break;
                    },
                },
                None => {
                    break;
                }
            }
        }

        match String::from_utf8(eaten) {
            Ok(string) => Some(Scalar(string)),
            Err(_) => None,
        }
    }

    fn consume(&mut self, edible: &'static str) -> bool {
        let mut eaten = Vec::new();
        for expected in edible.chars() {
            let character = self.pop();
            if character.is_some() {
                let c = character.unwrap();
                eaten.push(c as u8);
                if c == expected {
                    continue;
                }
            }
            for ate in eaten.drain().rev() {
                self.stack.push(ate);
            }
            return false;
        }
        true
    }
}

/// All the types of tokens
///
/// Describes all of the token types described by the [Yaml 1.0 Spec](http://yaml.org/spec/1.0/)
///
#[derive(PartialEq, Debug)]
pub enum Token {

    /// `[`: the start of a _flow_ sequence
    /// `c-sequence-start` in the spec
    SequenceStart,

    /// `]`: the end of a _flow_ sequence
    /// `c-sequence-end` in the spec
    SequenceEnd,

    /// `{`: the end of a _flow_ mapping
    /// `c-mapping-start` in the spec
    MappingStart,

    /// `}`: the end of a _flow_ mapping
    /// `c-mapping-end` in the spec
    MappingEnd,

    /// `-`: indicates an entry in a sequence
    /// `c-sequence-entry` in the spec
    SequenceEntry,

    /// `:`: separates key from value in a mapping
    /// `c-mapping-entry` in the spec
    MappingSeparator,

    /// `,`: separates entries in _flow_ collections (mapping or sequence)
    /// `c-collect-entry` in the spec
    CollectionSeparator,

    /// `?`: indicates a complex key (e.g a non-scalar key)
    /// `c-complex-key` in the spec
    ComplexKey,

    /// `!`: indicates a tag property
    /// `c-tag` in the spec
    Tag,

    /// `&`: indicates an anchor property (e.g setting a variable)
    /// `c-anchor` in the spec
    Anchor(String),

    /// `*`: indicates an anchor property (e.g using a variable)
    /// `c-alias` in the spec
    Alias(String),

    /// `|`: indicates a literal value (not to be escaped)
    /// `c-literal` in the spec
    Literal,

    /// `>`: indicates a folded value (ignore line breaks)
    /// `c-folded` in the spec
    Folded,

    /// `'`: a single quoted scalar
    /// `c-single-quote` in the spec
    SingleQuote,

    /// `"`: a double quoted scalar
    /// `c-double-quote` in the spec
    DoubleQuote,

    /// `#`: a comment
    /// `c-throwaway`
    Comment,

    /// `%YAML <version>`: a yaml version directive (tags for the YAML parser)
    /// `c-directive` in the spec
    YamlDirective(YamlVersion),

    /// TODO: `%<NAME> <param>*`: a directive yet to be implemented
    /// ``
    /// ReservedDirective(String, Vec<String>)

    /// `@ | \``: reserved for future use?
    /// `c-reserved` in the spec
    Reserved,

    ///TODO Documentation
    ///
    DocumentStart,

    ///TODO: Documentation
    ///
    DocumentEnd,

    /// ``: a line break with no specific purpose
    LineBreakGeneric,

    /// ``
    LineBreak(LineBreakType),

    Other, // A temporary addition for unimplemented tokens
    Scalar(String),
    Eof,
}

#[derive(PartialEq, Eq, Debug)]
pub struct YamlVersion {
    major: usize,
    minor: usize,
}

#[derive(PartialEq, Copy, Debug)]
pub enum LineBreakType {
    Generic,
    LineSeparator,
    ParagraphSeparator
}

impl <'a>Iterator for Tokenizer<'a> {

    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.next_token()
    }
}

mod test {

    use std::io::MemReader;
    use super::{Tokenizer, Token};
    use super::Token::*;

    #[test]
    fn test_look_ahead() {
        let stream = "--hallo";
        let mut reader = MemReader::new(stream.bytes().collect());
        let mut tokenizer = Tokenizer::new(Box::new(reader));
        let tokens: Vec<Token> = tokenizer.collect();
        assert!(tokens == vec![SequenceEntry, SequenceEntry, Scalar("hallo".to_string())]);
    }

    #[test]
    fn test_document() {
        let stream = "---\n    - hallo\n    - yolo\n...";
        let mut reader = MemReader::new(stream.bytes().collect());
        let mut tokenizer = Tokenizer::new(Box::new(reader));
        let tokens: Vec<Token> = tokenizer.collect();
        assert!(tokens == vec![
                DocumentStart,
                SequenceEntry,
                Scalar("hallo".to_string()),
                SequenceEntry,
                Scalar("yolo".to_string()),
                DocumentEnd
        ]);

    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Luis Casillas. See the COPYRIGHT file at the
// top-level directory of this distribution
//
// 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.

extern crate rand;

pub mod splittable {
    //! Traits to support splittable random number generators.
    //! References:
    //!
    //! * Claessen, Koen and Michał H. Pałka.  2013.  "Splittable
    //!   Pseudorandom Number Generators using Cryptographic Hashing."
    //!   *Haskell '13 Proceedings of the 2013 ACM SIGPLAN symposium
    //!   on Haskell*, pp. 47-58.
    //! * Schaathun, Hans Georg.  2015.  "Evaluation of Splittable
    //!   Pseudo-Random Generators."  *Journal of Functional
    //!   Programming*, Vol. 25.
    //! * The Haskell [`tf-random` library](https://hackage.haskell.org/package/tf-random)

    use rand::Rng;

    /// A trait for **splittable** pseudo random number generators,
    /// that support a "split" operations that produce two generators
    /// whose initial state depends on the source RNG's state, but
    /// produce statistically independent results.
    pub trait SplittableRng : Rng + Sized {

        /// The type of "splits" produced off a `SplittableRng`
        /// instance.
        type Split : SplitRng<Self>;

        /// Split this random number generator into "branches" that
        /// produce statistically independent results.
        ///
        /// The original generator is moved into this function, and
        /// can then no longer be reused.  This is deliberate; the
        /// Claessen & Pałka construction requires this.
        ///
        /// But the `Split` object returned from here supports
        /// instantiating the same branch multiple times.  This is
        /// also deliberate.
        fn splitn(self) -> Self::Split;

        /// Split this random number generator into two branches.
        /// This has a default implementation in terms of `splitn`.
        fn split(self) -> (Self, Self) {
            let splits: Self::Split = self.splitn();
            (splits.branch(0), splits.branch(1))
        }

    }

    /// The trait implemented by the "splits" of a `SplittableRng`.
    /// This should be seen as a factory for `usize`-indexed
    /// `SplittableRng` instances.
    pub trait SplitRng<R> {
        /// Instantiate the `i`th branch of the captured
        /// `SplittableRng`.
        ///
        /// Note that instantiating the same `i` multiple times is
        /// allowed; they all start from the same state.  This is
        /// useful in some cases; for example, random generation of
        /// deterministic functions (like Haskell's QuickCheck library
        /// does).
        fn branch(&self, i: usize) -> R;
    }

}

pub mod siprng {
    //! A splittable pseudo-random number generator based on the
    //! SipHash-1-3 function.  **This is not intended to be a
    //! cryptographically secure PRNG.**
    //!
    //! This generator is broadly modeled after the one described in
    //! this reference, and implemented in the Haskell [`tf-random`
    //! library](https://hackage.haskell.org/package/tf-random):
    //!
    //! * Claessen, Koen and Michał H. Pałka.  2013.  "Splittable
    //!   Pseudorandom Number Generators using Cryptographic Hashing."
    //!   *Haskell '13 Proceedings of the 2013 ACM SIGPLAN symposium
    //!   on Haskell*, pp. 47-58.
    //!
    //! Instead of the Skein hash function, however, we use
    //! SipHash-1-3 in counter mode.

    use rand::{Rand, Rng, SeedableRng};
    use splittable::{SplittableRng, SplitRng};
    use std::mem;

    #[derive(Clone)]
    pub struct SipRng {
        v0:  u64,
        v1:  u64,
        v2:  u64,
        v3:  u64,
        ctr: u64,
        len: usize
    }

    /// A "split" of a `SipRng`.
    pub struct SipRngSplit(SipRng);

    macro_rules! sipround {
        ($v0: expr, $v1: expr, $v2: expr, $v3: expr) => {
            $v0 = $v0.wrapping_add($v1); $v2 = $v2.wrapping_add($v3);
            $v1 = $v1.rotate_left(13);   $v3 = $v3.rotate_left(16);
            $v1 ^= $v0;                  $v3 ^= $v2;
            $v0 = $v0.rotate_left(32);

            $v2 = $v2.wrapping_add($v1); $v0 = $v0.wrapping_add($v3);
            $v1 = $v1.rotate_left(17);   $v3 = $v3.rotate_left(21);
            $v1 ^= $v2;                  $v3 ^= $v0;
            $v2 = $v0.rotate_left(32);
        }
    }

    const C0: u64 = 0x736f6d6570736575;
    const C1: u64 = 0x646f72616e646f6d;
    const C2: u64 = 0x6c7967656e657261;
    const C3: u64 = 0x7465646279746573;

    impl SipRng {
        pub fn new(k0: u64, k1: u64) -> SipRng {
            SipRng {
                v0:  k0 ^ C0,
                v1:  k1 ^ C1,
                v2:  k0 ^ C2,
                v3:  k1 ^ C3,
                ctr: 0,
                len: 1
            }
        }

        #[inline]
        fn advance(&mut self) {
            self.v3 ^= self.ctr;
            sipround!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= self.ctr;
            self.ctr.wrapping_add(1);
            // TODO: should we do something here if we hit zero again?
        }

        #[inline]
        fn descend(&mut self, branch: u64) {
            self.v3 ^= branch;
            sipround!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= branch;
            self.len.wrapping_add(1);
        }

    }

    impl SplitRng<SipRng> for SipRngSplit {
        fn branch(&self, i: usize) -> SipRng {
            let mut r = self.0.clone();
            r.descend(i as u64);
            r
        }
    }

    impl SplittableRng for SipRng {
        type Split = SipRngSplit;

        fn splitn(self) -> SipRngSplit {
            SipRngSplit(self)
        }

    }

    impl Rng for SipRng {
        #[inline]
        fn next_u64(&mut self) -> u64 {
            self.advance();
            let (mut v0, mut v1, mut v2, mut v3) =
                (self.v0, self.v1, self.v2, self.v3);

            let len = (self.len as u64).wrapping_shl(56);
            v3 ^= len;
            sipround!(v0, v1, v2, v3);
            v0 ^= len;

            v2 ^= 0xff;
            sipround!(v0, v1, v2, v3);
            sipround!(v0, v1, v2, v3);
            sipround!(v0, v1, v2, v3);
            v0 ^ v1 ^ v2 ^ v3
        }

        #[inline]
        fn next_u32(&mut self) -> u32 {
            self.next_u64() as u32
        }

        #[inline]
        fn fill_bytes(&mut self, dest: &mut [u8]) {
            for chunk in dest.chunks_mut(8) {
                let block = unsafe {
                    mem::transmute::<u64, [u8; 8]>(self.next_u64())
                };
                for i in 0..chunk.len() {
                    chunk[i] = block[i];
                }
            }
        }
    }

    impl SeedableRng<(u64, u64)> for SipRng {

        fn reseed(&mut self, seed: (u64, u64)) {
            self.v0 = seed.0 ^ C0;
            self.v1 = seed.1 ^ C1;
            self.v2 = seed.0 ^ C2;
            self.v3 = seed.1 ^ C3;
            self.len = 1;
            self.ctr = 0;
        }

        fn from_seed(seed: (u64, u64)) -> SipRng {
            let (k0, k1) = seed;
            SipRng::new(k0, k1)
        }
    }

    impl Rand for SipRng {
        fn rand<R: Rng>(other: &mut R) -> SipRng {
            let (k0, k1) = other.gen::<(u64, u64)>();
            SipRng::new(k0, k1)
        }
    }

}

#[cfg(test)]
mod tests {
    /*
     * I have shamelessly lifted a lot of these tests from the `rand`
     * crate.
     */

    use rand::{Rng, SeedableRng};
    use rand::os::OsRng;
    use siprng::SipRng;
    use splittable::SplittableRng;

    #[test]
    fn test_rng_rand_split() {
        let seed : (u64, u64) = gen_seed();

        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);

        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));

        let (mut ra0, mut ra1) = ra.split();
        let (mut rb0, mut rb1) = rb.split();

        assert!(iter_eq(ra0.gen_ascii_chars().take(100),
                        rb0.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra1.gen_ascii_chars().take(100),
                        rb1.gen_ascii_chars().take(100)));

        let (mut ra00, mut ra01) = ra0.split();
        let (mut ra10, mut ra11) = ra1.split();
        let (mut rb00, mut rb01) = rb0.split();
        let (mut rb10, mut rb11) = rb1.split();

        assert!(iter_eq(ra00.gen_ascii_chars().take(100),
                        rb00.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra01.gen_ascii_chars().take(100),
                        rb01.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra10.gen_ascii_chars().take(100),
                        rb10.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra11.gen_ascii_chars().take(100),
                        rb11.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_rand_seeded() {
        let seed : (u64, u64) = gen_seed();

        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);

        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_seeded() {
        let seed : (u64, u64) = gen_seed();
        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);
        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_reseed() {
        let seed : (u64, u64) = (1234567890, 987654321);
        let mut r: SipRng = SeedableRng::from_seed(seed);
        let string1: String = r.gen_ascii_chars().take(100).collect();

        r.reseed(seed);

        let string2: String = r.gen_ascii_chars().take(100).collect();
        assert_eq!(string1, string2);
    }

    #[test]
    fn test_rng_clone() {
        let seed : (u64, u64) = (0, 0);
        let mut rng: SipRng = SeedableRng::from_seed(seed);
        let mut clone = rng.clone();
        for _ in 0..16 {
            assert_eq!(rng.next_u64(), clone.next_u64());
        }
    }

    /*
     * Utility functions
     */

    fn gen_seed() -> (u64, u64) {
        let mut osrng = OsRng::new().ok().expect("Could not create OsRng");
        osrng.gen()
    }

    fn iter_eq<I, J>(i: I, j: J) -> bool
        where I: IntoIterator,
              J: IntoIterator<Item=I::Item>,
              I::Item: Eq
    {
        // make sure the iterators have equal length
        let mut i = i.into_iter();
        let mut j = j.into_iter();
        loop {
            match (i.next(), j.next()) {
                (Some(ref ei), Some(ref ej)) if ei == ej => { }
                (None, None) => return true,
                _ => return false,
            }
        }
    }
}
<commit_msg>Improve documentation.<commit_after>// Copyright 2016 Luis Casillas. See the COPYRIGHT file at the
// top-level directory of this distribution
//
// 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.

extern crate rand;

pub mod splittable {
    //! Traits to support splittable random number generators.
    //! References:
    //!
    //! * Claessen, Koen and Michał H. Pałka.  2013.  ["Splittable
    //!   Pseudorandom Number Generators using Cryptographic
    //!   Hashing."](http://publications.lib.chalmers.se/records/fulltext/183348/local_183348.pdf)
    //!   *Haskell '13: Proceedings of the 2013 ACM SIGPLAN symposium
    //!   on Haskell*, pp. 47-58.
    //! * Schaathun, Hans Georg.  2015.  ["Evaluation of Splittable
    //!   Pseudo-Random
    //!   Generators."](http://www.hg.schaathun.net/research/Papers/hgs2015jfp.pdf)
    //!   *Journal of Functional Programming*, Vol. 25.

    //! * The Haskell [`tf-random` library](https://hackage.haskell.org/package/tf-random).

    use rand::Rng;

    /// A trait for **splittable** pseudo random generators.  These
    /// are genertors that support a "split" operation that produces
    /// two or more "child" generators whose initial state depends on
    /// the source RNG's state, but produce outputs that are
    /// uncorrelated to each other.
    pub trait SplittableRng : Rng + Sized {

        /// The type of "splits" produced off a `SplittableRng`
        /// instance.  A split is an immutable object that captures
        /// the state of the RNG at the branching point, and serves as
        /// a factory for constructing RNGs for the "branches."
        type Split : SplitRng<Self>;

        /// Split this generator into branches.  Each branch is
        /// accessible from the resulting "split" object as a unique
        /// `usize` index.
        ///
        /// The original generator is moved into this function, and
        /// can then no longer be reused.  This is deliberate; the
        /// Claessen & Pałka construction requires this.
        ///
        /// But note that the `Split` object returned from here
        /// supports instantiating the same branch multiple times.
        /// This is also deliberate.
        fn splitn(self) -> Self::Split;

        /// Split this random number generator into two branches.
        /// This has a default implementation in terms of `splitn`.
        fn split(self) -> (Self, Self) {
            let splits: Self::Split = self.splitn();
            (splits.branch(0), splits.branch(1))
        }

    }

    /// The trait implemented by the "splits" of a `SplittableRng`.
    /// These objects act as immutable factories for `SplittableRng`
    /// instances, accessed by supplying an `usize` index.
    pub trait SplitRng<R> {
        /// Instantiate the `i`th branch of the captured
        /// `SplittableRng`.
        ///
        /// Note that instantiating the same `i` multiple times is
        /// allowed, and they all start from the same state.  This is
        /// useful in some cases; for example, random generation of
        /// deterministic functions (like Haskell's QuickCheck library
        /// does).
        fn branch(&self, i: usize) -> R;
    }

}

pub mod siprng {

    use rand::{Rand, Rng, SeedableRng};
    use splittable::{SplittableRng, SplitRng};
    use std::mem;

    /// A splittable pseudo-random number generator based on the
    /// SipHash-1-3 function.  **This is not intended to be a
    /// cryptographically secure PRNG.**
    ///
    /// This generator is broadly modeled after Claessen and Pałka's,
    /// a version of which is implemented in the Haskell [`tf-random`
    /// library](https://hackage.haskell.org/package/tf-random).
    /// Instead of the Skein hash function, however, we use
    /// SipHash-1-3 as the pseudo-random function.
    ///
    /// References:
    ///
    /// * Aumasson, Jean-Philippe and Daniel J. Bernstein.  2012.
    ///   ["SipHash: a fast short-input
    ///   PRF."](https://eprint.iacr.org/2012/351) Cryptology ePrint
    ///   Archive, Report 2012/351.
    /// * Claessen, Koen and Michał H. Pałka.  2013.  ["Splittable
    ///   Pseudorandom Number Generators using Cryptographic
    ///   Hashing."](http://publications.lib.chalmers.se/records/fulltext/183348/local_183348.pdf)
    ///   *Haskell '13: Proceedings of the 2013 ACM SIGPLAN symposium
    ///   on Haskell*, pp. 47-58.
    /// * The Haskell [`tf-random` library](https://hackage.haskell.org/package/tf-random).
    #[derive(Clone)]
    pub struct SipRng {
        v0:  u64,
        v1:  u64,
        v2:  u64,
        v3:  u64,
        ctr: u64,
        len: usize
    }

    /// A "split" of a `SipRng`.
    pub struct SipRngSplit(SipRng);

    macro_rules! sipround {
        ($v0: expr, $v1: expr, $v2: expr, $v3: expr) => {
            $v0 = $v0.wrapping_add($v1); $v2 = $v2.wrapping_add($v3);
            $v1 = $v1.rotate_left(13);   $v3 = $v3.rotate_left(16);
            $v1 ^= $v0;                  $v3 ^= $v2;
            $v0 = $v0.rotate_left(32);

            $v2 = $v2.wrapping_add($v1); $v0 = $v0.wrapping_add($v3);
            $v1 = $v1.rotate_left(17);   $v3 = $v3.rotate_left(21);
            $v1 ^= $v2;                  $v3 ^= $v0;
            $v2 = $v0.rotate_left(32);
        }
    }

    const C0: u64 = 0x736f6d6570736575;
    const C1: u64 = 0x646f72616e646f6d;
    const C2: u64 = 0x6c7967656e657261;
    const C3: u64 = 0x7465646279746573;

    impl SipRng {
        /// Create a `SipRng` generator from two `u64`s given as seed.
        pub fn new(k0: u64, k1: u64) -> SipRng {
            SipRng {
                v0:  k0 ^ C0,
                v1:  k1 ^ C1,
                v2:  k0 ^ C2,
                v3:  k1 ^ C3,
                ctr: 0,
                len: 1
            }
        }

        #[inline]
        fn advance(&mut self) {
            self.v3 ^= self.ctr;
            sipround!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= self.ctr;
            self.ctr.wrapping_add(1);
            // TODO: should we do something here if we hit zero again?
        }

        #[inline]
        fn descend(&mut self, branch: u64) {
            self.v3 ^= branch;
            sipround!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= branch;
            self.len.wrapping_add(1);
        }

    }

    impl SplitRng<SipRng> for SipRngSplit {
        fn branch(&self, i: usize) -> SipRng {
            let mut r = self.0.clone();
            r.descend(i as u64);
            r
        }
    }

    impl SplittableRng for SipRng {
        type Split = SipRngSplit;

        fn splitn(self) -> SipRngSplit {
            SipRngSplit(self)
        }

    }

    impl Rng for SipRng {
        #[inline]
        fn next_u64(&mut self) -> u64 {
            self.advance();
            let (mut v0, mut v1, mut v2, mut v3) =
                (self.v0, self.v1, self.v2, self.v3);

            let len = (self.len as u64).wrapping_shl(56);
            v3 ^= len;
            sipround!(v0, v1, v2, v3);
            v0 ^= len;

            v2 ^= 0xff;
            sipround!(v0, v1, v2, v3);
            sipround!(v0, v1, v2, v3);
            sipround!(v0, v1, v2, v3);
            v0 ^ v1 ^ v2 ^ v3
        }

        #[inline]
        fn next_u32(&mut self) -> u32 {
            self.next_u64() as u32
        }

        #[inline]
        fn fill_bytes(&mut self, dest: &mut [u8]) {
            for chunk in dest.chunks_mut(8) {
                let block = unsafe {
                    mem::transmute::<u64, [u8; 8]>(self.next_u64())
                };
                for i in 0..chunk.len() {
                    chunk[i] = block[i];
                }
            }
        }
    }

    impl SeedableRng<(u64, u64)> for SipRng {

        fn reseed(&mut self, seed: (u64, u64)) {
            self.v0 = seed.0 ^ C0;
            self.v1 = seed.1 ^ C1;
            self.v2 = seed.0 ^ C2;
            self.v3 = seed.1 ^ C3;
            self.len = 1;
            self.ctr = 0;
        }

        fn from_seed(seed: (u64, u64)) -> SipRng {
            let (k0, k1) = seed;
            SipRng::new(k0, k1)
        }
    }

    impl Rand for SipRng {
        fn rand<R: Rng>(other: &mut R) -> SipRng {
            let (k0, k1) = other.gen::<(u64, u64)>();
            SipRng::new(k0, k1)
        }
    }

}

#[cfg(test)]
mod tests {
    /*
     * I have shamelessly lifted a lot of these tests from the `rand`
     * crate.
     */

    use rand::{Rng, SeedableRng};
    use rand::os::OsRng;
    use siprng::SipRng;
    use splittable::SplittableRng;

    #[test]
    fn test_rng_rand_split() {
        let seed : (u64, u64) = gen_seed();

        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);

        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));

        let (mut ra0, mut ra1) = ra.split();
        let (mut rb0, mut rb1) = rb.split();

        assert!(iter_eq(ra0.gen_ascii_chars().take(100),
                        rb0.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra1.gen_ascii_chars().take(100),
                        rb1.gen_ascii_chars().take(100)));

        let (mut ra00, mut ra01) = ra0.split();
        let (mut ra10, mut ra11) = ra1.split();
        let (mut rb00, mut rb01) = rb0.split();
        let (mut rb10, mut rb11) = rb1.split();

        assert!(iter_eq(ra00.gen_ascii_chars().take(100),
                        rb00.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra01.gen_ascii_chars().take(100),
                        rb01.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra10.gen_ascii_chars().take(100),
                        rb10.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra11.gen_ascii_chars().take(100),
                        rb11.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_rand_seeded() {
        let seed : (u64, u64) = gen_seed();

        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);

        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_seeded() {
        let seed : (u64, u64) = gen_seed();
        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);
        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_reseed() {
        let seed : (u64, u64) = (1234567890, 987654321);
        let mut r: SipRng = SeedableRng::from_seed(seed);
        let string1: String = r.gen_ascii_chars().take(100).collect();

        r.reseed(seed);

        let string2: String = r.gen_ascii_chars().take(100).collect();
        assert_eq!(string1, string2);
    }

    #[test]
    fn test_rng_clone() {
        let seed : (u64, u64) = (0, 0);
        let mut rng: SipRng = SeedableRng::from_seed(seed);
        let mut clone = rng.clone();
        for _ in 0..16 {
            assert_eq!(rng.next_u64(), clone.next_u64());
        }
    }

    /*
     * Utility functions
     */

    fn gen_seed() -> (u64, u64) {
        let mut osrng = OsRng::new().ok().expect("Could not create OsRng");
        osrng.gen()
    }

    fn iter_eq<I, J>(i: I, j: J) -> bool
        where I: IntoIterator,
              J: IntoIterator<Item=I::Item>,
              I::Item: Eq
    {
        // make sure the iterators have equal length
        let mut i = i.into_iter();
        let mut j = j.into_iter();
        loop {
            match (i.next(), j.next()) {
                (Some(ref ei), Some(ref ej)) if ei == ej => { }
                (None, None) => return true,
                _ => return false,
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

mod ffi;

use std::marker::Send;

use ffi::*;

struct ParserContext<'a, H: ParserHandler + 'a> {
    parser: &'a mut Parser,
    handler: &'a mut H,
}

#[inline]
unsafe fn unwrap_context<'a, H: ParserHandler>(http: *mut HttpParser) -> &'a mut ParserContext<'a, H> {
    &mut *((*http).data as *mut ParserContext<H>)
}

macro_rules! notify_fn_wrapper {
    ( $callback:ident ) => ({
        extern "C" fn $callback<H: ParserHandler>(http: *mut HttpParser) -> libc::c_int {
            let mut context = unsafe { unwrap_context::<H>(http) };
            if context.handler.$callback(context.parser) { 0 } else { 1 }
        };

        $callback::<H>
    });
}

macro_rules! data_fn_wrapper {
    ( $callback:ident ) => ({
        extern "C" fn $callback<H: ParserHandler>(http: *mut HttpParser, data: *const u32, size: libc::size_t) -> libc::c_int {
            let slice = unsafe { std::slice::from_raw_parts(data as *const u8, size as usize) };
            let mut context = unsafe { unwrap_context::<H>(http) };
            if context.handler.$callback(context.parser, slice) { 0 } else { 1 }
        };

        $callback::<H>
    });
}

impl HttpParserSettings {
    fn new<H: ParserHandler>() -> HttpParserSettings {
        HttpParserSettings {
            on_url: data_fn_wrapper!(on_url),
            on_message_begin: notify_fn_wrapper!(on_message_begin),
            on_status: data_fn_wrapper!(on_status),
            on_header_field: data_fn_wrapper!(on_header_field),
            on_header_value: data_fn_wrapper!(on_header_value),
            on_headers_complete: notify_fn_wrapper!(on_headers_complete),
            on_body: data_fn_wrapper!(on_body),
            on_message_complete: notify_fn_wrapper!(on_message_complete),
            on_chunk_header: notify_fn_wrapper!(on_chunk_header),
            on_chunk_complete: notify_fn_wrapper!(on_chunk_complete),
        }
    }
}

// High level Rust interface

/// Used to define a set of callbacks in your code.
/// They would be called by the parser whenever new data is available.
/// You should bear in mind that the data might get in your callbacks in a partial form.
///
/// Return `bool` as a result of each function call - either
/// `true` for the "OK, go on" status, or `false` when you want to stop
/// the parser after the function call has ended.
///
/// All callbacks provide a default no-op implementation (i.e. they just return `true`).
///
#[allow(unused_variables)]
pub trait ParserHandler: Sized {
    /// Called when the URL part of a request becomes available.
    /// E.g. for `GET /forty-two HTTP/1.1` it will be called with `"/forty_two"` argument.
    ///
    /// It's not called in the response mode.
    fn on_url(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Called when a response status becomes available.
    ///
    /// It's not called in the request mode.
    fn on_status(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Called for each HTTP header key part.
    fn on_header_field(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Called for each HTTP header value part.
    fn on_header_value(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Called with body text as an argument when the new part becomes available.
    fn on_body(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Notified when all available headers have been processed.
    fn on_headers_complete(&mut self, &mut Parser) -> bool {
        true
    }

    /// Notified when the parser receives first bytes to parse.
    fn on_message_begin(&mut self, &mut Parser) -> bool {
        true
    }

    /// Notified when the parser has finished its job.
    fn on_message_complete(&mut self, &mut Parser) -> bool {
        true
    }

    fn on_chunk_header(&mut self, &mut Parser) -> bool {
        true
    }
    fn on_chunk_complete(&mut self, &mut Parser) -> bool {
        true
    }
}

fn http_method_name(method_code: u8) -> &'static str {
    unsafe {
        let method_str = http_method_str(method_code);
        let buf = std::ffi::CStr::from_ptr(method_str);
        return std::str::from_utf8(buf.to_bytes()).unwrap();
    }
}

fn _http_errno_name(errno: u8) -> &'static str {
    unsafe {
        let err_str = http_errno_name(errno);
        let buf = std::ffi::CStr::from_ptr(err_str);
        return std::str::from_utf8(buf.to_bytes()).unwrap();
    }
}

fn _http_errno_description(errno: u8) -> &'static str {
    unsafe {
        let err_str = http_errno_description(errno);
        let buf = std::ffi::CStr::from_ptr(err_str);
        return std::str::from_utf8(buf.to_bytes()).unwrap();
    }
}

/// The main parser interface.
///
/// # Example
/// ```ignore
/// struct MyHandler;
/// impl ParserHandler for MyHandler {
///    fn on_header_field(&self, header: &[u8]) -> bool {
///        println!("{}: ", header);
///        true
///    }
///    fn on_header_value(&self, value: &[u8]) -> bool {
///        println!("\t {}", value);
///        true
///    }
/// }
///
/// let http_request = b"GET / HTTP/1.0\r\n\
///                      Content-Length: 0\r\n\r\n";
///
/// Parser::request(&MyHandler).parse(http_request);
/// ```
#[allow(dead_code)]
pub struct Parser {
    state: HttpParser,
    parser_type: ParserType,
    flags: u32,
}

unsafe impl Send for Parser {}

impl Parser {
    /// Creates a new parser instance for an HTTP response.
    pub fn response() -> Parser {
        Parser {
            parser_type: ParserType::HttpResponse,
            state: HttpParser::new(ParserType::HttpResponse),
            flags: 0,
        }
    }

    /// Creates a new parser instance for an HTTP request.
    pub fn request() -> Parser {
        Parser {
            parser_type: ParserType::HttpRequest,
            state: HttpParser::new(ParserType::HttpRequest),
            flags: 0,
        }
    }

    /// Creates a new parser instance to handle both HTTP requests and responses.
    pub fn request_and_response() -> Parser {
        Parser {
            parser_type: ParserType::HttpBoth,
            state: HttpParser::new(ParserType::HttpBoth),
            flags: 0,
        }
    }

    /// Parses the provided `data` and returns a number of bytes read.
    pub fn parse<H: ParserHandler>(&mut self, handler: &mut H, data: &[u8]) -> usize {
        unsafe {
            let mut context = ParserContext {
                parser: self,
                handler: handler,
            };

            context.parser.state.data = &mut context as *mut _ as *mut libc::c_void;

            let size =
                http_parser_execute(&mut context.parser.state as *mut _,
                                    &HttpParserSettings::new::<H>() as *const _,
                                    data.as_ptr(),
                                    data.len() as libc::size_t) as usize;

            context.parser.flags = http_get_struct_flags(&context.parser.state as *const _);

            size
        }
    }

    /// Returns an HTTP request or response version.
    pub fn http_version(&self) -> (u16, u16) {
        (self.state.http_major, self.state.http_minor)
    }

    /// Returns an HTTP response status code (think *404*).
    pub fn status_code(&self) -> u16 {
        return (self.flags & 0xFFFF) as u16;
    }

    /// Returns an HTTP method static string (`GET`, `POST`, and so on).
    pub fn http_method(&self) -> &'static str {
        let method_code = ((self.flags >> 16) & 0xFF) as u8;
        return http_method_name(method_code);
    }

    fn http_errnum(&self) -> u8 {
        return ((self.flags >> 24) & 0x7F) as u8;
    }

    /// Checks if the last `parse` call was finished successfully.
    /// Returns `true` if it wasn't.
    pub fn has_error(&self) -> bool {
        self.http_errnum() != 0x00
    }

    /// In case of a parsing error returns its mnemonic name.
    pub fn error(&self) -> &'static str {
        _http_errno_name(self.http_errnum())
    }

    /// In case of a parsing error returns its description.
    pub fn error_description(&self) -> &'static str {
        _http_errno_description(self.http_errnum())
    }

    /// Checks if an upgrade protocol (e.g. WebSocket) was requested.
    pub fn is_upgrade(&self) -> bool {
        return ((self.flags >> 31) & 0x01) == 1;
    }

    /// Checks if it was the final body chunk.
    pub fn is_final_chunk(&self) -> bool {
        return self.state.http_body_is_final() == 1;
    }

    /// If `should_keep_alive()` in the `on_headers_complete` or `on_message_complete` callback
    /// returns 0, then this should be the last message on the connection.
    /// If you are the server, respond with the "Connection: close" header.
    /// If you are the client, close the connection.
    pub fn should_keep_alive(&self) -> bool {
        self.state.http_should_keep_alive() == 1
    }
}

impl std::fmt::Debug for Parser {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        let (version_major, version_minor) = self.http_version();
        return write!(fmt,
                      "status_code: {}\nmethod: {}\nerror: {}, {}\nupgrade: {}\nhttp_version: \
                       {}.{}",
                      self.status_code(),
                      self.http_method(),
                      self.error(),
                      self.error_description(),
                      self.is_upgrade(),
                      version_major,
                      version_minor);
    }
}

/// Returns a version of the underlying `http-parser` library.
pub fn version() -> (u32, u32, u32) {
    let version = unsafe { http_parser_version() };

    let major = (version >> 16) & 255;
    let minor = (version >> 8) & 255;
    let patch = version & 255;

    (major, minor, patch)
}

#[cfg(test)]
mod tests {
    use super::{version, ParserHandler, Parser};

    #[test]
    fn test_version() {
        assert_eq!((2, 7, 1), version());
    }

    #[test]
    fn test_request_parser() {
        struct TestRequestParser;

        impl ParserHandler for TestRequestParser {
            fn on_url(&mut self, _: &mut Parser, url: &[u8]) -> bool {
                assert_eq!(b"/say_hello", url);
                true
            }

            fn on_header_field(&mut self, _: &mut Parser, hdr: &[u8]) -> bool {
                assert!(hdr == b"Host" || hdr == b"Content-Length");
                true
            }

            fn on_header_value(&mut self, _: &mut Parser, val: &[u8]) -> bool {
                assert!(val == b"localhost.localdomain" || val == b"11");
                true
            }

            fn on_body(&mut self, parser: &mut Parser, body: &[u8]) -> bool {
                assert_eq!((1, 1), parser.http_version());
                assert_eq!(body, b"Hello world");
                true
            }
        }

        let req = b"POST /say_hello HTTP/1.1\r\nContent-Length: 11\r\nHost: localhost.localdomain\r\n\r\nHello world";

        let mut handler = TestRequestParser;

        let mut parser = Parser::request();
        let parsed = parser.parse(&mut handler, req);

        assert!(parsed > 0);
        assert!(!parser.has_error());
        assert_eq!("POST", parser.http_method());
    }

    #[test]
    fn test_response_parser() {
        struct TestResponseParser;

        impl ParserHandler for TestResponseParser {
            fn on_status(&mut self, _: &mut Parser, status: &[u8]) -> bool {
                assert_eq!(b"OK", status);
                true
            }

            fn on_header_field(&mut self, _: &mut Parser, hdr: &[u8]) -> bool {
                assert_eq!(b"Host", hdr);
                true
            }

            fn on_header_value(&mut self, _: &mut Parser, val: &[u8]) -> bool {
                assert_eq!(b"localhost.localdomain", val);
                true
            }
        }

        let req = b"HTTP/1.1 200 OK\r\nHost: localhost.localdomain\r\n\r\n";

        let mut handler = TestResponseParser;

        let mut parser = Parser::response();
        let parsed = parser.parse(&mut handler, req);

        assert!(parsed > 0);
        assert!(!parser.has_error());
        assert_eq!((1, 1), parser.http_version());
        assert_eq!(200, parser.status_code());
    }

    #[test]
    fn test_ws_upgrade() {
        struct DummyHandler;

        impl ParserHandler for DummyHandler {};

        let req = b"GET / HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n";

        let mut handler = DummyHandler;

        let mut parser = Parser::request();
        parser.parse(&mut handler, req);

        assert_eq!(parser.is_upgrade(), true);
    }

    #[test]
    fn test_error_status() {
        struct DummyHandler {
            url_parsed: bool,
        }

        impl ParserHandler for DummyHandler {
            fn on_url(&mut self, _: &mut Parser, _: &[u8]) -> bool {
                self.url_parsed = true;
                false
            }

            fn on_header_field(&mut self, _: &mut Parser, _: &[u8]) -> bool {
                panic!("This callback shouldn't be executed!");
            }
        }

        let req = b"GET / HTTP/1.1\r\nHeader: hello\r\n\r\n";

        let mut handler = DummyHandler { url_parsed: false };

        let mut parser = Parser::request();
        parser.parse(&mut handler, req);

        assert!(handler.url_parsed);
    }

    #[test]
    fn test_streaming() {
        struct DummyHandler;

        impl ParserHandler for DummyHandler {};

        let req = b"GET / HTTP/1.1\r\nHeader: hello\r\n\r\n";

        let mut handler = DummyHandler;
        let mut parser = Parser::request();

        parser.parse(&mut handler, &req[0..10]);

        assert_eq!(parser.http_version(), (0, 0));
        assert!(!parser.has_error());

        parser.parse(&mut handler, &req[10..]);

        assert_eq!(parser.http_version(), (1, 1));
    }

    #[test]
    fn test_catch_error() {
        struct DummyHandler;

        impl ParserHandler for DummyHandler {};

        let req = b"UNKNOWN_METHOD / HTTP/3.0\r\nAnswer: 42\r\n\r\n";

        let mut handler = DummyHandler;
        let mut parser = Parser::request();

        parser.parse(&mut handler, req);

        assert!(parser.has_error());
        assert_eq!(parser.error(), "HPE_INVALID_METHOD");
    }
}
<commit_msg>Fix rustdoc example #16<commit_after>extern crate libc;

mod ffi;

use std::marker::Send;

use ffi::*;

struct ParserContext<'a, H: ParserHandler + 'a> {
    parser: &'a mut Parser,
    handler: &'a mut H,
}

#[inline]
unsafe fn unwrap_context<'a, H: ParserHandler>(http: *mut HttpParser) -> &'a mut ParserContext<'a, H> {
    &mut *((*http).data as *mut ParserContext<H>)
}

macro_rules! notify_fn_wrapper {
    ( $callback:ident ) => ({
        extern "C" fn $callback<H: ParserHandler>(http: *mut HttpParser) -> libc::c_int {
            let mut context = unsafe { unwrap_context::<H>(http) };
            if context.handler.$callback(context.parser) { 0 } else { 1 }
        };

        $callback::<H>
    });
}

macro_rules! data_fn_wrapper {
    ( $callback:ident ) => ({
        extern "C" fn $callback<H: ParserHandler>(http: *mut HttpParser, data: *const u32, size: libc::size_t) -> libc::c_int {
            let slice = unsafe { std::slice::from_raw_parts(data as *const u8, size as usize) };
            let mut context = unsafe { unwrap_context::<H>(http) };
            if context.handler.$callback(context.parser, slice) { 0 } else { 1 }
        };

        $callback::<H>
    });
}

impl HttpParserSettings {
    fn new<H: ParserHandler>() -> HttpParserSettings {
        HttpParserSettings {
            on_url: data_fn_wrapper!(on_url),
            on_message_begin: notify_fn_wrapper!(on_message_begin),
            on_status: data_fn_wrapper!(on_status),
            on_header_field: data_fn_wrapper!(on_header_field),
            on_header_value: data_fn_wrapper!(on_header_value),
            on_headers_complete: notify_fn_wrapper!(on_headers_complete),
            on_body: data_fn_wrapper!(on_body),
            on_message_complete: notify_fn_wrapper!(on_message_complete),
            on_chunk_header: notify_fn_wrapper!(on_chunk_header),
            on_chunk_complete: notify_fn_wrapper!(on_chunk_complete),
        }
    }
}

// High level Rust interface

/// Used to define a set of callbacks in your code.
/// They would be called by the parser whenever new data is available.
/// You should bear in mind that the data might get in your callbacks in a partial form.
///
/// Return `bool` as a result of each function call - either
/// `true` for the "OK, go on" status, or `false` when you want to stop
/// the parser after the function call has ended.
///
/// All callbacks provide a default no-op implementation (i.e. they just return `true`).
///
#[allow(unused_variables)]
pub trait ParserHandler: Sized {
    /// Called when the URL part of a request becomes available.
    /// E.g. for `GET /forty-two HTTP/1.1` it will be called with `"/forty_two"` argument.
    ///
    /// It's not called in the response mode.
    fn on_url(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Called when a response status becomes available.
    ///
    /// It's not called in the request mode.
    fn on_status(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Called for each HTTP header key part.
    fn on_header_field(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Called for each HTTP header value part.
    fn on_header_value(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Called with body text as an argument when the new part becomes available.
    fn on_body(&mut self, &mut Parser, &[u8]) -> bool {
        true
    }

    /// Notified when all available headers have been processed.
    fn on_headers_complete(&mut self, &mut Parser) -> bool {
        true
    }

    /// Notified when the parser receives first bytes to parse.
    fn on_message_begin(&mut self, &mut Parser) -> bool {
        true
    }

    /// Notified when the parser has finished its job.
    fn on_message_complete(&mut self, &mut Parser) -> bool {
        true
    }

    fn on_chunk_header(&mut self, &mut Parser) -> bool {
        true
    }
    fn on_chunk_complete(&mut self, &mut Parser) -> bool {
        true
    }
}

fn http_method_name(method_code: u8) -> &'static str {
    unsafe {
        let method_str = http_method_str(method_code);
        let buf = std::ffi::CStr::from_ptr(method_str);
        return std::str::from_utf8(buf.to_bytes()).unwrap();
    }
}

fn _http_errno_name(errno: u8) -> &'static str {
    unsafe {
        let err_str = http_errno_name(errno);
        let buf = std::ffi::CStr::from_ptr(err_str);
        return std::str::from_utf8(buf.to_bytes()).unwrap();
    }
}

fn _http_errno_description(errno: u8) -> &'static str {
    unsafe {
        let err_str = http_errno_description(errno);
        let buf = std::ffi::CStr::from_ptr(err_str);
        return std::str::from_utf8(buf.to_bytes()).unwrap();
    }
}

/// The main parser interface.
///
/// # Example
/// ```
/// use http_muncher::{Parser, ParserHandler};
/// use std::str;
///
/// struct MyHandler;
/// impl ParserHandler for MyHandler {
///    fn on_header_field(&mut self, parser: &mut Parser, header: &[u8]) -> bool {
///        println!("{}: ", str::from_utf8(header).unwrap());
///        true
///    }
///    fn on_header_value(&mut self, parser: &mut Parser, value: &[u8]) -> bool {
///        println!("\t {:?}", str::from_utf8(value).unwrap());
///        true
///    }
/// }
///
/// let http_request = b"GET / HTTP/1.0\r\n\
///                      Content-Length: 0\r\n\r\n";
///
/// let mut parser = Parser::request();
/// parser.parse(&mut MyHandler {}, http_request);
/// ```
#[allow(dead_code)]
pub struct Parser {
    state: HttpParser,
    parser_type: ParserType,
    flags: u32,
}

unsafe impl Send for Parser {}

impl Parser {
    /// Creates a new parser instance for an HTTP response.
    pub fn response() -> Parser {
        Parser {
            parser_type: ParserType::HttpResponse,
            state: HttpParser::new(ParserType::HttpResponse),
            flags: 0,
        }
    }

    /// Creates a new parser instance for an HTTP request.
    pub fn request() -> Parser {
        Parser {
            parser_type: ParserType::HttpRequest,
            state: HttpParser::new(ParserType::HttpRequest),
            flags: 0,
        }
    }

    /// Creates a new parser instance to handle both HTTP requests and responses.
    pub fn request_and_response() -> Parser {
        Parser {
            parser_type: ParserType::HttpBoth,
            state: HttpParser::new(ParserType::HttpBoth),
            flags: 0,
        }
    }

    /// Parses the provided `data` and returns a number of bytes read.
    pub fn parse<H: ParserHandler>(&mut self, handler: &mut H, data: &[u8]) -> usize {
        unsafe {
            let mut context = ParserContext {
                parser: self,
                handler: handler,
            };

            context.parser.state.data = &mut context as *mut _ as *mut libc::c_void;

            let size =
                http_parser_execute(&mut context.parser.state as *mut _,
                                    &HttpParserSettings::new::<H>() as *const _,
                                    data.as_ptr(),
                                    data.len() as libc::size_t) as usize;

            context.parser.flags = http_get_struct_flags(&context.parser.state as *const _);

            size
        }
    }

    /// Returns an HTTP request or response version.
    pub fn http_version(&self) -> (u16, u16) {
        (self.state.http_major, self.state.http_minor)
    }

    /// Returns an HTTP response status code (think *404*).
    pub fn status_code(&self) -> u16 {
        return (self.flags & 0xFFFF) as u16;
    }

    /// Returns an HTTP method static string (`GET`, `POST`, and so on).
    pub fn http_method(&self) -> &'static str {
        let method_code = ((self.flags >> 16) & 0xFF) as u8;
        return http_method_name(method_code);
    }

    fn http_errnum(&self) -> u8 {
        return ((self.flags >> 24) & 0x7F) as u8;
    }

    /// Checks if the last `parse` call was finished successfully.
    /// Returns `true` if it wasn't.
    pub fn has_error(&self) -> bool {
        self.http_errnum() != 0x00
    }

    /// In case of a parsing error returns its mnemonic name.
    pub fn error(&self) -> &'static str {
        _http_errno_name(self.http_errnum())
    }

    /// In case of a parsing error returns its description.
    pub fn error_description(&self) -> &'static str {
        _http_errno_description(self.http_errnum())
    }

    /// Checks if an upgrade protocol (e.g. WebSocket) was requested.
    pub fn is_upgrade(&self) -> bool {
        return ((self.flags >> 31) & 0x01) == 1;
    }

    /// Checks if it was the final body chunk.
    pub fn is_final_chunk(&self) -> bool {
        return self.state.http_body_is_final() == 1;
    }

    /// If `should_keep_alive()` in the `on_headers_complete` or `on_message_complete` callback
    /// returns 0, then this should be the last message on the connection.
    /// If you are the server, respond with the "Connection: close" header.
    /// If you are the client, close the connection.
    pub fn should_keep_alive(&self) -> bool {
        self.state.http_should_keep_alive() == 1
    }
}

impl std::fmt::Debug for Parser {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        let (version_major, version_minor) = self.http_version();
        return write!(fmt,
                      "status_code: {}\nmethod: {}\nerror: {}, {}\nupgrade: {}\nhttp_version: \
                       {}.{}",
                      self.status_code(),
                      self.http_method(),
                      self.error(),
                      self.error_description(),
                      self.is_upgrade(),
                      version_major,
                      version_minor);
    }
}

/// Returns a version of the underlying `http-parser` library.
pub fn version() -> (u32, u32, u32) {
    let version = unsafe { http_parser_version() };

    let major = (version >> 16) & 255;
    let minor = (version >> 8) & 255;
    let patch = version & 255;

    (major, minor, patch)
}

#[cfg(test)]
mod tests {
    use super::{version, ParserHandler, Parser};

    #[test]
    fn test_version() {
        assert_eq!((2, 7, 1), version());
    }

    #[test]
    fn test_request_parser() {
        struct TestRequestParser;

        impl ParserHandler for TestRequestParser {
            fn on_url(&mut self, _: &mut Parser, url: &[u8]) -> bool {
                assert_eq!(b"/say_hello", url);
                true
            }

            fn on_header_field(&mut self, _: &mut Parser, hdr: &[u8]) -> bool {
                assert!(hdr == b"Host" || hdr == b"Content-Length");
                true
            }

            fn on_header_value(&mut self, _: &mut Parser, val: &[u8]) -> bool {
                assert!(val == b"localhost.localdomain" || val == b"11");
                true
            }

            fn on_body(&mut self, parser: &mut Parser, body: &[u8]) -> bool {
                assert_eq!((1, 1), parser.http_version());
                assert_eq!(body, b"Hello world");
                true
            }
        }

        let req = b"POST /say_hello HTTP/1.1\r\nContent-Length: 11\r\nHost: localhost.localdomain\r\n\r\nHello world";

        let mut handler = TestRequestParser;

        let mut parser = Parser::request();
        let parsed = parser.parse(&mut handler, req);

        assert!(parsed > 0);
        assert!(!parser.has_error());
        assert_eq!("POST", parser.http_method());
    }

    #[test]
    fn test_response_parser() {
        struct TestResponseParser;

        impl ParserHandler for TestResponseParser {
            fn on_status(&mut self, _: &mut Parser, status: &[u8]) -> bool {
                assert_eq!(b"OK", status);
                true
            }

            fn on_header_field(&mut self, _: &mut Parser, hdr: &[u8]) -> bool {
                assert_eq!(b"Host", hdr);
                true
            }

            fn on_header_value(&mut self, _: &mut Parser, val: &[u8]) -> bool {
                assert_eq!(b"localhost.localdomain", val);
                true
            }
        }

        let req = b"HTTP/1.1 200 OK\r\nHost: localhost.localdomain\r\n\r\n";

        let mut handler = TestResponseParser;

        let mut parser = Parser::response();
        let parsed = parser.parse(&mut handler, req);

        assert!(parsed > 0);
        assert!(!parser.has_error());
        assert_eq!((1, 1), parser.http_version());
        assert_eq!(200, parser.status_code());
    }

    #[test]
    fn test_ws_upgrade() {
        struct DummyHandler;

        impl ParserHandler for DummyHandler {};

        let req = b"GET / HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n";

        let mut handler = DummyHandler;

        let mut parser = Parser::request();
        parser.parse(&mut handler, req);

        assert_eq!(parser.is_upgrade(), true);
    }

    #[test]
    fn test_error_status() {
        struct DummyHandler {
            url_parsed: bool,
        }

        impl ParserHandler for DummyHandler {
            fn on_url(&mut self, _: &mut Parser, _: &[u8]) -> bool {
                self.url_parsed = true;
                false
            }

            fn on_header_field(&mut self, _: &mut Parser, _: &[u8]) -> bool {
                panic!("This callback shouldn't be executed!");
            }
        }

        let req = b"GET / HTTP/1.1\r\nHeader: hello\r\n\r\n";

        let mut handler = DummyHandler { url_parsed: false };

        let mut parser = Parser::request();
        parser.parse(&mut handler, req);

        assert!(handler.url_parsed);
    }

    #[test]
    fn test_streaming() {
        struct DummyHandler;

        impl ParserHandler for DummyHandler {};

        let req = b"GET / HTTP/1.1\r\nHeader: hello\r\n\r\n";

        let mut handler = DummyHandler;
        let mut parser = Parser::request();

        parser.parse(&mut handler, &req[0..10]);

        assert_eq!(parser.http_version(), (0, 0));
        assert!(!parser.has_error());

        parser.parse(&mut handler, &req[10..]);

        assert_eq!(parser.http_version(), (1, 1));
    }

    #[test]
    fn test_catch_error() {
        struct DummyHandler;

        impl ParserHandler for DummyHandler {};

        let req = b"UNKNOWN_METHOD / HTTP/3.0\r\nAnswer: 42\r\n\r\n";

        let mut handler = DummyHandler;
        let mut parser = Parser::request();

        parser.parse(&mut handler, req);

        assert!(parser.has_error());
        assert_eq!(parser.error(), "HPE_INVALID_METHOD");
    }
}
<|endoftext|>


<commit_before>#![crate_name = "input"]
#![deny(missing_doc)]
#![feature(globs)]
#![feature(struct_variant)]

//! A flexible structure for user interactions
//! to be used in window frameworks and widgets libraries.

pub mod keyboard;
pub mod mouse;

/// Models different kinds of buttons.
#[deriving(Clone, PartialEq, Eq, Show)]
pub enum Button {
    /// A keyboard button.
    Keyboard(keyboard::Key),
    /// A mouse button.
    Mouse(mouse::Button),
}

/// Models different kinds of motion.
#[deriving(Clone, Show)]
pub enum Motion {
    /// x and y in window coordinates.
    MouseCursor(f64, f64),
    /// x and y in relative coordinates.
    MouseRelative(f64, f64),
    /// x and y in scroll ticks.
    MouseScroll(f64, f64),
}

/// Models input events.
#[deriving(Clone, Show)]
pub enum InputEvent {
    /// Pressed a button.
    Press(Button),
    /// Released a button.
    Release(Button),
    /// Moved mouse cursor.
    Move(Motion),
    /// Text (usually from keyboard).
    Text(String),
}

<commit_msg>Added Resize event<commit_after>#![crate_name = "input"]
#![deny(missing_doc)]
#![feature(globs)]
#![feature(struct_variant)]

//! A flexible structure for user interactions
//! to be used in window frameworks and widgets libraries.

pub mod keyboard;
pub mod mouse;

/// Models different kinds of buttons.
#[deriving(Clone, PartialEq, Eq, Show)]
pub enum Button {
    /// A keyboard button.
    Keyboard(keyboard::Key),
    /// A mouse button.
    Mouse(mouse::Button),
}

/// Models different kinds of motion.
#[deriving(Clone, Show)]
pub enum Motion {
    /// x and y in window coordinates.
    MouseCursor(f64, f64),
    /// x and y in relative coordinates.
    MouseRelative(f64, f64),
    /// x and y in scroll ticks.
    MouseScroll(f64, f64),
}

/// Models input events.
#[deriving(Clone, Show)]
pub enum InputEvent {
    /// Pressed a button.
    Press(Button),
    /// Released a button.
    Release(Button),
    /// Moved mouse cursor.
    Move(Motion),
    /// Text (usually from keyboard).
    Text(String),
    /// Window got resized.
    Resize(u32, u32),
}

<|endoftext|>