<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

//! SimpleStream crate.

#![allow(dead_code)]

extern crate libc;
extern crate errno;

use std::{mem, ptr};
use std::result::Result;
use std::net::TcpStream;
use std::os::unix::io::{RawFd, AsRawFd};

use self::errno::errno;
use self::libc::consts::os::posix88;
use self::libc::{size_t, c_void, c_int, ssize_t};

use util::*;
use readbuffer::ReadBuffer;

pub mod util;
mod message;
mod readbuffer;

extern "C" {
    fn read(fd: c_int, buffer: *mut c_void, count: size_t) -> ssize_t;
    fn write(fd: c_int, buffer: *const c_void, cout: size_t) -> ssize_t;
}

/// Represents the result of trying to create a new SimpleStream
pub type CreateResult = Result<SimpleStream, FnctlError>;

/// Represents the result of attempting a read on the underlying file descriptor
pub type ReadResult = Result<(), ReadError>;

/// Represents the result attempting a write on the underlying fild descriptor
pub type WriteResult = Result<u16, WriteError>;

/// States the current stream can be in
#[derive(PartialEq, Clone)]
pub enum ReadState {
    /// Currently reading the payload length
    PayloadLen,
    /// Currently reading the payload
    Payload
}

/// Struct representing a simple messaging protocol over Tcp sockets
pub struct SimpleStream {
    /// Current state
    state: ReadState,
    /// Underlying std::net::TcpStream
    stream: TcpStream,
    /// Message buffer
    buffer: ReadBuffer
}

impl SimpleStream {

    /// Attempts to create a new SimpleStream from a TcpStream
    pub fn new(stream: TcpStream) -> CreateResult {
        let fd = stream.as_raw_fd();
        let mut response;
        unsafe {
            response = libc::fcntl(
                fd,
                libc::consts::os::posix01::F_SETFL,
                libc::consts::os::extra::O_NONBLOCK);
        }

        if response < 0 {
            let errno = errno().0 as i32;
            return match errno {
                posix88::EAGAIN     => Err(FnctlError::EAGAIN),
                posix88::EBADF      => Err(FnctlError::EBADF),
                posix88::EDEADLK    => Err(FnctlError::EDEADLK),
                posix88::EFAULT     => Err(FnctlError::EFAULT),
                posix88::EINTR      => Err(FnctlError::EINTR),
                posix88::EINVAL     => Err(FnctlError::EINVAL),
                posix88::EMFILE     => Err(FnctlError::EMFILE),
                posix88::ENOLCK     => Err(FnctlError::ENOLCK),
                posix88::EPERM      => Err(FnctlError::EPERM),
                _ => panic!("Unexpected errno: {}", errno)
            };
        }

        Ok(SimpleStream {
            state: ReadState::PayloadLen,
            stream: stream,
            buffer: ReadBuffer::new()
        })
    }

    /// Performs a read on the underlying fd. Places all received messages into
    /// the queue in the ReadBuffer. Reads until EAGAIN is hit.
    pub fn read(&mut self) -> ReadResult {
        // We need to loop until EAGAIN is hit from read_num_bytes.
        // Epoll is set to EdgeTrigged mode, which will let us known when there
        // is data to be read on the file descriptor, but if we do not clear it
        // all in this run we will lose whatever we do not grab.
        loop {
            let count = self.buffer.remaining();
            let result = self.read_num_bytes(count);
            if result.is_err() {
                let err = result.unwrap_err();
                match err {
                    ReadError::EAGAIN => {
                        return Ok(())
                    }
                    _ => return Err(err)
                }
            }

            if self.buffer.remaining() == 0 {
                if self.state == ReadState::PayloadLen {
                    self.buffer.calc_payload_len();
                    let p_len = self.buffer.payload_len();
                    self.buffer.set_capacity(p_len);
                    self.state = ReadState::Payload;
                } else { // Payload completely read
                    self.buffer.reset();
                    self.state = ReadState::PayloadLen;
                }
            }
        }
    }

    /// Attempts to read num bytes from the underlying file descriptor.
    fn read_num_bytes(&mut self, num: u16) -> ReadResult {
        let fd = self.stream.as_raw_fd();

        // Create a buffer, size num
        let mut buffer;
        unsafe {
            buffer = libc::calloc(num as size_t,
                mem::size_of::<u8>() as size_t);
        }

        // Ensure system gave up dynamic memory
        if buffer.is_null() {
            return Err(ReadError::ENOMEM)
        }

        // Attempt to read available data into buffer
        let mut num_read;
        unsafe {
            num_read = read(fd, buffer, num as size_t);
        }

        // Return on error
        if num_read < 0 {
            unsafe { libc::free(buffer); }
            let errno = errno().0 as i32;
            return match errno {
                posix88::ENOMEM         => Err(ReadError::ENOMEM),
                posix88::EBADF          => Err(ReadError::EBADF),
                posix88::EFAULT         => Err(ReadError::EFAULT),
                posix88::EINTR          => Err(ReadError::EINTR),
                posix88::EINVAL         => Err(ReadError::EINVAL),
                posix88::EIO            => Err(ReadError::EIO),
                posix88::EISDIR         => Err(ReadError::EISDIR),

                // These two constants can have the same value on some systems,
                // but different values on others, so we can't use a match
                // clause
                x if x == posix88::EAGAIN || x == posix88::EWOULDBLOCK =>
                    Err(ReadError::EAGAIN),

                _ => panic!("Unexpected errno during read: {}", errno)
            };
        }

        // Check for EOF
        if num_read == 0 {
            unsafe { libc::free(buffer); }
            return Err(ReadError::EOF);
        }

        // Add bytes to msg buffer
        for x in 0..num_read as isize {
            unsafe {
                self.buffer.push(ptr::read(buffer.offset(x)) as u8);
            }
        }

        // Free buffer and return Ok
        unsafe { libc::free(buffer); }
        Ok(())
    }

    /// Attempts to write the buffer to the underlying file descriptor
    pub fn write(&mut self, buffer: &Vec<u8>) -> WriteResult {
        let mut plen_buf = [0u8; 2];
        plen_buf[0] = (buffer.len() as u16 & 0b1111_1111u16 << 8) as u8;
        plen_buf[1] = (buffer.len() as u16 & 0b1111_1111u16) as u8;

        let mut n_buffer = Vec::<u8>::with_capacity(buffer.len() + 2);
        n_buffer.push(plen_buf[0]);
        n_buffer.push(plen_buf[1]);

        for x in 0..buffer.len() {
            n_buffer.push(buffer[x]);
        }

        self.write_bytes(&mut n_buffer)
    }

    /// Attempts to write the passed buffer to the underlying file descriptor
    fn write_bytes(&mut self, buffer: &mut Vec<u8>) -> WriteResult {
        let fd = self.stream.as_raw_fd();

        let mut num_written;
        unsafe {
            let buf_slc = &buffer[..];
            let buf_ptr = buf_slc.as_ptr();
            let v_ptr: *const c_void = mem::transmute(buf_ptr);
            num_written = write(fd,
                v_ptr,
                buffer.len() as size_t);
        }

        if num_written < 0 {
            let errno = errno().0 as i32;
            return match errno {
                posix88::EBADF          => Err(WriteError::EBADF),
                posix88::EDESTADDRREQ   => Err(WriteError::EDESTADDRREQ),
                posix88::EDQUOT         => Err(WriteError::EDQUOT),
                posix88::EFAULT         => Err(WriteError::EFAULT),
                posix88::EFBIG          => Err(WriteError::EFBIG),
                posix88::EINTR          => Err(WriteError::EINTR),
                posix88::EINVAL         => Err(WriteError::EINVAL),
                posix88::EIO            => Err(WriteError::EIO),
                posix88::ENOSPC         => Err(WriteError::ENOSPC),
                posix88::EPIPE          => Err(WriteError::EPIPE),

                // These two constants can have the same value on some systems,
                // but different values on others, so we can't use a match
                // clause
                x if x == posix88::EAGAIN || x == posix88::EWOULDBLOCK =>
                    Err(WriteError::EAGAIN),

                _ => panic!("Unknown errno during write: {}", errno),
            }
        }

        Ok(num_written as u16)
    }

    /// Returns the underlying file descriptor
    pub fn raw_fd(&self) -> RawFd {
        self.stream.as_raw_fd()
    }

    /// Returns a mutable reference to the internal ReadBuffer
    pub fn buffer_as_mut(&mut self) -> &mut ReadBuffer {
        &mut self.buffer
    }
}

impl Clone for SimpleStream {
    fn clone(&self) -> SimpleStream {
        SimpleStream {
            state: self.state.clone(),
            stream: self.stream.try_clone().unwrap(),
            buffer: self.buffer.clone()
        }
    }
}
<commit_msg>Readbuffer is public<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

//! SimpleStream crate.

#![allow(dead_code)]

extern crate libc;
extern crate errno;

use std::{mem, ptr};
use std::result::Result;
use std::net::TcpStream;
use std::os::unix::io::{RawFd, AsRawFd};

use self::errno::errno;
use self::libc::consts::os::posix88;
use self::libc::{size_t, c_void, c_int, ssize_t};

use util::*;
use readbuffer::ReadBuffer;

pub mod util;
pub mod readbuffer;

mod message;

extern "C" {
    fn read(fd: c_int, buffer: *mut c_void, count: size_t) -> ssize_t;
    fn write(fd: c_int, buffer: *const c_void, cout: size_t) -> ssize_t;
}

/// Represents the result of trying to create a new SimpleStream
pub type CreateResult = Result<SimpleStream, FnctlError>;

/// Represents the result of attempting a read on the underlying file descriptor
pub type ReadResult = Result<(), ReadError>;

/// Represents the result attempting a write on the underlying fild descriptor
pub type WriteResult = Result<u16, WriteError>;

/// States the current stream can be in
#[derive(PartialEq, Clone)]
pub enum ReadState {
    /// Currently reading the payload length
    PayloadLen,
    /// Currently reading the payload
    Payload
}

/// Struct representing a simple messaging protocol over Tcp sockets
pub struct SimpleStream {
    /// Current state
    state: ReadState,
    /// Underlying std::net::TcpStream
    stream: TcpStream,
    /// Message buffer
    buffer: ReadBuffer
}

impl SimpleStream {

    /// Attempts to create a new SimpleStream from a TcpStream
    pub fn new(stream: TcpStream) -> CreateResult {
        let fd = stream.as_raw_fd();
        let mut response;
        unsafe {
            response = libc::fcntl(
                fd,
                libc::consts::os::posix01::F_SETFL,
                libc::consts::os::extra::O_NONBLOCK);
        }

        if response < 0 {
            let errno = errno().0 as i32;
            return match errno {
                posix88::EAGAIN     => Err(FnctlError::EAGAIN),
                posix88::EBADF      => Err(FnctlError::EBADF),
                posix88::EDEADLK    => Err(FnctlError::EDEADLK),
                posix88::EFAULT     => Err(FnctlError::EFAULT),
                posix88::EINTR      => Err(FnctlError::EINTR),
                posix88::EINVAL     => Err(FnctlError::EINVAL),
                posix88::EMFILE     => Err(FnctlError::EMFILE),
                posix88::ENOLCK     => Err(FnctlError::ENOLCK),
                posix88::EPERM      => Err(FnctlError::EPERM),
                _ => panic!("Unexpected errno: {}", errno)
            };
        }

        Ok(SimpleStream {
            state: ReadState::PayloadLen,
            stream: stream,
            buffer: ReadBuffer::new()
        })
    }

    /// Performs a read on the underlying fd. Places all received messages into
    /// the queue in the ReadBuffer. Reads until EAGAIN is hit.
    pub fn read(&mut self) -> ReadResult {
        // We need to loop until EAGAIN is hit from read_num_bytes.
        // Epoll is set to EdgeTrigged mode, which will let us known when there
        // is data to be read on the file descriptor, but if we do not clear it
        // all in this run we will lose whatever we do not grab.
        loop {
            let count = self.buffer.remaining();
            let result = self.read_num_bytes(count);
            if result.is_err() {
                let err = result.unwrap_err();
                match err {
                    ReadError::EAGAIN => {
                        return Ok(())
                    }
                    _ => return Err(err)
                }
            }

            if self.buffer.remaining() == 0 {
                if self.state == ReadState::PayloadLen {
                    self.buffer.calc_payload_len();
                    let p_len = self.buffer.payload_len();
                    self.buffer.set_capacity(p_len);
                    self.state = ReadState::Payload;
                } else { // Payload completely read
                    self.buffer.reset();
                    self.state = ReadState::PayloadLen;
                }
            }
        }
    }

    /// Attempts to read num bytes from the underlying file descriptor.
    fn read_num_bytes(&mut self, num: u16) -> ReadResult {
        let fd = self.stream.as_raw_fd();

        // Create a buffer, size num
        let mut buffer;
        unsafe {
            buffer = libc::calloc(num as size_t,
                mem::size_of::<u8>() as size_t);
        }

        // Ensure system gave up dynamic memory
        if buffer.is_null() {
            return Err(ReadError::ENOMEM)
        }

        // Attempt to read available data into buffer
        let mut num_read;
        unsafe {
            num_read = read(fd, buffer, num as size_t);
        }

        // Return on error
        if num_read < 0 {
            unsafe { libc::free(buffer); }
            let errno = errno().0 as i32;
            return match errno {
                posix88::ENOMEM         => Err(ReadError::ENOMEM),
                posix88::EBADF          => Err(ReadError::EBADF),
                posix88::EFAULT         => Err(ReadError::EFAULT),
                posix88::EINTR          => Err(ReadError::EINTR),
                posix88::EINVAL         => Err(ReadError::EINVAL),
                posix88::EIO            => Err(ReadError::EIO),
                posix88::EISDIR         => Err(ReadError::EISDIR),

                // These two constants can have the same value on some systems,
                // but different values on others, so we can't use a match
                // clause
                x if x == posix88::EAGAIN || x == posix88::EWOULDBLOCK =>
                    Err(ReadError::EAGAIN),

                _ => panic!("Unexpected errno during read: {}", errno)
            };
        }

        // Check for EOF
        if num_read == 0 {
            unsafe { libc::free(buffer); }
            return Err(ReadError::EOF);
        }

        // Add bytes to msg buffer
        for x in 0..num_read as isize {
            unsafe {
                self.buffer.push(ptr::read(buffer.offset(x)) as u8);
            }
        }

        // Free buffer and return Ok
        unsafe { libc::free(buffer); }
        Ok(())
    }

    /// Attempts to write the buffer to the underlying file descriptor
    pub fn write(&mut self, buffer: &Vec<u8>) -> WriteResult {
        let mut plen_buf = [0u8; 2];
        plen_buf[0] = (buffer.len() as u16 & 0b1111_1111u16 << 8) as u8;
        plen_buf[1] = (buffer.len() as u16 & 0b1111_1111u16) as u8;

        let mut n_buffer = Vec::<u8>::with_capacity(buffer.len() + 2);
        n_buffer.push(plen_buf[0]);
        n_buffer.push(plen_buf[1]);

        for x in 0..buffer.len() {
            n_buffer.push(buffer[x]);
        }

        self.write_bytes(&mut n_buffer)
    }

    /// Attempts to write the passed buffer to the underlying file descriptor
    fn write_bytes(&mut self, buffer: &mut Vec<u8>) -> WriteResult {
        let fd = self.stream.as_raw_fd();

        let mut num_written;
        unsafe {
            let buf_slc = &buffer[..];
            let buf_ptr = buf_slc.as_ptr();
            let v_ptr: *const c_void = mem::transmute(buf_ptr);
            num_written = write(fd,
                v_ptr,
                buffer.len() as size_t);
        }

        if num_written < 0 {
            let errno = errno().0 as i32;
            return match errno {
                posix88::EBADF          => Err(WriteError::EBADF),
                posix88::EDESTADDRREQ   => Err(WriteError::EDESTADDRREQ),
                posix88::EDQUOT         => Err(WriteError::EDQUOT),
                posix88::EFAULT         => Err(WriteError::EFAULT),
                posix88::EFBIG          => Err(WriteError::EFBIG),
                posix88::EINTR          => Err(WriteError::EINTR),
                posix88::EINVAL         => Err(WriteError::EINVAL),
                posix88::EIO            => Err(WriteError::EIO),
                posix88::ENOSPC         => Err(WriteError::ENOSPC),
                posix88::EPIPE          => Err(WriteError::EPIPE),

                // These two constants can have the same value on some systems,
                // but different values on others, so we can't use a match
                // clause
                x if x == posix88::EAGAIN || x == posix88::EWOULDBLOCK =>
                    Err(WriteError::EAGAIN),

                _ => panic!("Unknown errno during write: {}", errno),
            }
        }

        Ok(num_written as u16)
    }

    /// Returns the underlying file descriptor
    pub fn raw_fd(&self) -> RawFd {
        self.stream.as_raw_fd()
    }

    /// Returns a mutable reference to the internal ReadBuffer
    pub fn buffer_as_mut(&mut self) -> &mut ReadBuffer {
        &mut self.buffer
    }
}

impl Clone for SimpleStream {
    fn clone(&self) -> SimpleStream {
        SimpleStream {
            state: self.state.clone(),
            stream: self.stream.try_clone().unwrap(),
            buffer: self.buffer.clone()
        }
    }
}
<|endoftext|>


<commit_before>/// Library to parse and execute brainfuck programs

use std::error::Error;
use std::fmt;
use std::io::stdin;

pub use self::Command::*;
pub use self::Ast::*;

/// Brainfuck command
#[derive(Debug)]
pub enum Command {
    IncPointer,
    DecPointer,
    IncData,
    DecData,
    GetByte,
    PutByte,
}

/// Node in a brainfuck AST
#[derive(Debug)]
pub enum Ast {
    Op(Command),
    Loop(Program),
}

/// A brainfuck program is just a list of AST nodes
pub type Program = Vec<Ast>;

/// Context in which a brainfuck program executes
#[derive(Debug)]
pub struct Context {
    dp: usize,
    data: Vec<u8>,
}

impl Context {
    /// build a new program context initialized with all zeroes
    pub fn new() -> Context {
        Context { dp: 0, data: Vec::with_capacity(100) }
    }

    /// execute program `p` in this context
    pub fn execute(&mut self, p: &Program) -> Result<(), String> {
        for node in p {
            let cur_data = self.cur_data();
            match *node {
                Op(IncPointer) => self.dp += 1,
                Op(DecPointer) => self.dp -= 1,
                Op(IncData)    => self.set_cur_data(cur_data + 1),
                Op(DecData)    => self.set_cur_data(cur_data - 1),
                Op(GetByte)    => self.set_cur_data(try!(Context::getbyte())),
                Op(PutByte)    => print!("{:}", self.cur_data() as char),
                Loop(ref x)    =>  {
                    while self.getdata(self.dp) != 0 {
                        try!(self.execute(x))
                    }
                },
            }
        }
        Ok(())
    }

    /// set data cell at `address` to `value`
    ///
    /// It is preferred that you use this rather than accessing the data cell
    /// directly, as this will ensure the address is in face allocated,
    /// preventing panics
    pub fn setdata(&mut self, address: usize, value: u8) {
        if address >= self.data.len() {
            let diff = address - self.data.len() + 1;
            self.data.extend((0..diff).map(|_| 0u8));

            // after we extend, address should be within bounds
            assert!(address < self.data.len());
        };
        self.data[address] = value;
    }

    /// get data cell at `address`
    ///
    /// It is preferred that you use this rather than accessing the data cell
    /// directly, as this will ensure the address is in face allocated,
    /// preventing panics
    pub fn getdata(&self, address: usize) -> u8 {
        if address >= self.data.len() { 0 } else { self.data[address] }
    }

    fn cur_data(&self) -> u8 {
        self.getdata(self.dp)
    }

    fn set_cur_data(&mut self, value: u8) {
        let dp = self.dp;
        self.setdata(dp, value)
    }

    fn getbyte() -> Result<u8, String> {
        loop {
            let mut input = String::new();
            println!("enter single byte: ");
            try!(stdin().read_line(&mut input)
                .map_err(|e| format!("could not read char: {}", e)));

            if input.len() > 1 {
                println!("only a single char, please");
                continue;
            } else if (input.chars().next().unwrap() as u32) > 256 {
                println!("char must fit in a single byte");
                continue;
            } else {
                return Ok(input.as_bytes()[0]);
            }
        }
    }
}

/// Used for parsing errors
#[derive(Debug)]
pub struct ParseError {
    description: String
}

impl ParseError {
    fn new(d: &str) -> ParseError {
        ParseError { description: d.to_string() }
    }
}

impl Error for ParseError {
    fn description(&self) -> &str { &self.description }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "ParseError: {}", self.description)
    }
}

enum ParseResult {
    Some(Ast),
    Ignore,
    LoopEnd,
    Err(ParseError),
}

/// parse a brainfuck program
///
/// # Failures
/// There's not many texts that aren't valid as a brainfuck program. This
/// function will only error in the case of unbalanced '[]' tokens
pub fn parse<T>(stream: &mut T) -> Result<Program, ParseError>
    where T: Iterator<Item=char>
{
    let mut program: Program = Vec::with_capacity(20);
    while let Some(c) = stream.next() {
        use self::ParseResult::*;
        match parse_char(c, stream) {
            Some(ast) => program.push(ast),
            Ignore => continue,
            LoopEnd => return Result::Err(ParseError::new("extra ']'")),
            Err(x) => return Result::Err(x)
        }
    }
    Ok(program)
}

fn parse_char<T>(c: char, stream: &mut T) -> ParseResult
    where T: Iterator<Item=char>
{
    use self::ParseResult::*;
    match c {
        '>' => Some(Op(IncPointer)),
        '<' => Some(Op(DecPointer)),
        '+' => Some(Op(IncData)),
        '-' => Some(Op(DecData)),
        ',' => Some(Op(GetByte)),
        '.' => Some(Op(PutByte)),
        '[' => parse_loop(stream),
        ']' => LoopEnd,
        _   => Ignore,
    }
}

fn parse_loop<T>(stream: &mut T) -> ParseResult
    where T: Iterator<Item=char>
{
    let mut commands: Program = Vec::with_capacity(20);
    loop {
        if let Some(c) = stream.next() {
            use self::ParseResult::*;
            match parse_char(c, stream) {
                Some(ast) => commands.push(ast),
                Ignore => continue,
                LoopEnd => break,
                x => return x,
            }
        } else {
            let err = ParseError::new("Missing ']' character");
            return ParseResult::Err(err);
        }
    }
    ParseResult::Some(Loop(commands))
}
<commit_msg>comment spelling fix<commit_after>/// Library to parse and execute brainfuck programs

use std::error::Error;
use std::fmt;
use std::io::stdin;

pub use self::Command::*;
pub use self::Ast::*;

/// Brainfuck command
#[derive(Debug)]
pub enum Command {
    IncPointer,
    DecPointer,
    IncData,
    DecData,
    GetByte,
    PutByte,
}

/// Node in a brainfuck AST
#[derive(Debug)]
pub enum Ast {
    Op(Command),
    Loop(Program),
}

/// A brainfuck program is just a list of AST nodes
pub type Program = Vec<Ast>;

/// Context in which a brainfuck program executes
#[derive(Debug)]
pub struct Context {
    dp: usize,
    data: Vec<u8>,
}

impl Context {
    /// build a new program context initialized with all zeroes
    pub fn new() -> Context {
        Context { dp: 0, data: Vec::with_capacity(100) }
    }

    /// execute program `p` in this context
    pub fn execute(&mut self, p: &Program) -> Result<(), String> {
        for node in p {
            let cur_data = self.cur_data();
            match *node {
                Op(IncPointer) => self.dp += 1,
                Op(DecPointer) => self.dp -= 1,
                Op(IncData)    => self.set_cur_data(cur_data + 1),
                Op(DecData)    => self.set_cur_data(cur_data - 1),
                Op(GetByte)    => self.set_cur_data(try!(Context::getbyte())),
                Op(PutByte)    => print!("{:}", self.cur_data() as char),
                Loop(ref x)    =>  {
                    while self.getdata(self.dp) != 0 {
                        try!(self.execute(x))
                    }
                },
            }
        }
        Ok(())
    }

    /// set data cell at `address` to `value`
    ///
    /// It is preferred that you use this rather than accessing the data cell
    /// directly, as this will ensure the address is in fact allocated,
    /// preventing panics
    pub fn setdata(&mut self, address: usize, value: u8) {
        if address >= self.data.len() {
            let diff = address - self.data.len() + 1;
            self.data.extend((0..diff).map(|_| 0u8));

            // after we extend, address should be within bounds
            assert!(address < self.data.len());
        };
        self.data[address] = value;
    }

    /// get data cell at `address`
    ///
    /// It is preferred that you use this rather than accessing the data cell
    /// directly, as this will ensure the address is in fact allocated,
    /// preventing panics
    pub fn getdata(&self, address: usize) -> u8 {
        if address >= self.data.len() { 0 } else { self.data[address] }
    }

    fn cur_data(&self) -> u8 {
        self.getdata(self.dp)
    }

    fn set_cur_data(&mut self, value: u8) {
        let dp = self.dp;
        self.setdata(dp, value)
    }

    fn getbyte() -> Result<u8, String> {
        loop {
            let mut input = String::new();
            println!("enter single byte: ");
            try!(stdin().read_line(&mut input)
                .map_err(|e| format!("could not read char: {}", e)));

            if input.len() > 1 {
                println!("only a single char, please");
                continue;
            } else if (input.chars().next().unwrap() as u32) > 256 {
                println!("char must fit in a single byte");
                continue;
            } else {
                return Ok(input.as_bytes()[0]);
            }
        }
    }
}

/// Used for parsing errors
#[derive(Debug)]
pub struct ParseError {
    description: String
}

impl ParseError {
    fn new(d: &str) -> ParseError {
        ParseError { description: d.to_string() }
    }
}

impl Error for ParseError {
    fn description(&self) -> &str { &self.description }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "ParseError: {}", self.description)
    }
}

enum ParseResult {
    Some(Ast),
    Ignore,
    LoopEnd,
    Err(ParseError),
}

/// parse a brainfuck program
///
/// # Failures
/// There's not many texts that aren't valid as a brainfuck program. This
/// function will only error in the case of unbalanced '[]' tokens
pub fn parse<T>(stream: &mut T) -> Result<Program, ParseError>
    where T: Iterator<Item=char>
{
    let mut program: Program = Vec::with_capacity(20);
    while let Some(c) = stream.next() {
        use self::ParseResult::*;
        match parse_char(c, stream) {
            Some(ast) => program.push(ast),
            Ignore => continue,
            LoopEnd => return Result::Err(ParseError::new("extra ']'")),
            Err(x) => return Result::Err(x)
        }
    }
    Ok(program)
}

fn parse_char<T>(c: char, stream: &mut T) -> ParseResult
    where T: Iterator<Item=char>
{
    use self::ParseResult::*;
    match c {
        '>' => Some(Op(IncPointer)),
        '<' => Some(Op(DecPointer)),
        '+' => Some(Op(IncData)),
        '-' => Some(Op(DecData)),
        ',' => Some(Op(GetByte)),
        '.' => Some(Op(PutByte)),
        '[' => parse_loop(stream),
        ']' => LoopEnd,
        _   => Ignore,
    }
}

fn parse_loop<T>(stream: &mut T) -> ParseResult
    where T: Iterator<Item=char>
{
    let mut commands: Program = Vec::with_capacity(20);
    loop {
        if let Some(c) = stream.next() {
            use self::ParseResult::*;
            match parse_char(c, stream) {
                Some(ast) => commands.push(ast),
                Ignore => continue,
                LoopEnd => break,
                x => return x,
            }
        } else {
            let err = ParseError::new("Missing ']' character");
            return ParseResult::Err(err);
        }
    }
    ParseResult::Some(Loop(commands))
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Write, Read, BufRead, BufReader};

mod chars;
mod value;
mod cmd;
mod state;
mod err;

use chars::*;
use value::Value;
use value::Value::*;
use cmd::Command;
use cmd::Command::*;
pub use state::State;
pub use err::{Result, Error};

pub struct InOuter<W: Write, R: Read> {
    o: W,
    i: BufReader<R>,
}

impl<W: Write, R: Read> InOuter<W, R> {
    pub fn new(o: W, i: R) -> Self {
        InOuter {
            o,
            i: BufReader::new(i),
        }
    }
    pub fn extract(self) -> (W, R) {
        let InOuter{i, o} = self;
        (o, i.into_inner())
    }
}

pub fn run_with_state<R, R2, W>(src: R, state: &mut State, io: &mut InOuter<W, R2>) -> Result<()>
where R: Read, R2: Read, W: Write {
    let mut buf = String::new();
    let mut ignoring_whitespace = false;

    for c in src.chars_iterator() {
        match c {
            Ok(c) => {
                if c.is_whitespace() && !ignoring_whitespace {
                    if !buf.is_empty() {
                        run_command(state, Command::from_str(&buf), io)?;
                        buf.clear();
                    }
                } else {
                    if c == '"' {
                        ignoring_whitespace = !ignoring_whitespace;
                    }
                    buf.push(c);
                }
            },
            Err(e) => return Err(Error::CharsError(e))
        }
    }

    Ok(())
}

fn binop<T: Into<Value>, F: FnOnce(Value, Value) -> T>(s: &mut State, f: F) -> Result<()> {
    let b = s.pop()?;
    let a = s.pop()?;

    s.push(f(a, b).into());
    Ok(())
}

use std::ops;
use std::mem::replace;

fn run_command<W: Write, R: Read>(state: &mut State, cmd: Command, io: &mut InOuter<W, R>) -> Result<()> {
    if cfg!(feature = "debug") {
        println!("{f}  {indent}{:?}: {:?}", cmd, state.stack(),
            f = if cmd == BeginBlock {"\n"}else{""},
            indent = "    ".repeat((state.block_nesting as usize)
            .saturating_sub(if cmd == EndBlock {1}else{0})),
        );
    }

    match cmd {
        EndBlock => match state.block_nesting {
            0 => return Err(Error::NoBlockStarted),
            1 => {
                state.block_nesting = 0;

                let t = replace(&mut state.temp, Vec::new());
                state.push(Block(1, t));
            }
            _ => {
                state.block_nesting -= 1;
                state.temp.push(EndBlock);
            }
        }
        BeginBlock => {
            state.block_nesting += 1;
            if state.block_nesting > 1 {
                state.temp.push(BeginBlock);
            }
        }
        ref cmd if state.block_nesting > 0 => state.temp.push(cmd.clone()),
        Value(s) => if s.starts_with('"') {
            state.push(Str(s[1..s.len()-1].to_owned()));
        } else if let Ok(n) = s.parse::<f64>() {
            state.push(Num(n));
        } else {
            let to_push;
            if let Some(v) = state.get_var(&s) {
                to_push = v.clone();
            } else {
                to_push = Variable(s);
            }
            state.push(to_push);
        }
        EmptyBlock => state.push(Block(1, Vec::new())),
        Include => {
            match state.pop()? {
                Str(s) => {
                    let file = File::open(s)?;
                    run_with_state(file, state, io)?;
                }
                _ => return Err(Error::InvalidIncludeArg)
            }
        }
        True => state.push(Num(1.)),
        False => state.push(Num(0.)),
        NullVal => state.push(Value::Null),
        Size => {
            let size = state.stack().len() as f64;
            state.push(Num(size))
        }
        Length => {
            let to_push = match *state.peek()? {
                Block(n, ref b) => Num((n as usize * b.len()) as f64),
                Str(ref s) => Num(s.chars().count() as f64),
                _ => Null
            };
            state.push(to_push);
        }
        Dup => {
            let dup = state.peek()?.clone();
            state.push(dup);
        }
        Not => {
            let a = state.pop()?;
            state.push(!a);
        }
        If => {
            let when_false = state.pop()?;
            let when_true = state.pop()?;
            let condition = state.pop()?;

            state.push(if condition.as_bool() {
                when_true
            } else {
                when_false
            });
        }
        Assign => {
            match (state.pop()?, state.pop()?) {
                (Variable(_), Variable(_)) => return Err(Error::InvalidAssignArg),
                (Variable(h), v) | (v, Variable(h)) => state.add_var(h, v),
                _ => return Err(Error::InvalidAssignArg),
            }
        }
        ApplyFunction => {
            match state.pop()? {
                Block(n, b) => {
                    for _ in 0..n {
                        for cmd in &b {
                            run_command(state, cmd.clone(), io)?;
                        }
                    }
                }
                _ => return Err(Error::InvalidApplyArg)
            }
        }
        Read => {
            let mut line = String::new();
            io.i.read_line(&mut line)?;
            line = line.trim_right().to_owned();
            state.push(Str(line));
        }
        Swap => {
            let a = state.pop()?;
            let b = state.pop()?;
            state.push(a);
            state.push(b);
        }
        Split => {
            let i = match state.pop()? {
                Num(n) => n,
                _ => return Err(Error::InvalidSplitArg)
            } as usize;

            match state.pop()?.flatten() {
                Block(n, mut b) => {
                    debug_assert_eq!(n, 1, "value has been flattened");

                    let i = b.len().checked_sub(i).ok_or(Error::OutOfBounds)?;

                    let right = b.split_off(i);
                    state.push(Block(1, b));
                    state.push(Block(1, right));
                }
                Str(mut s) => {
                    let len = s.chars().count();
                    let byte_len = s.len();

                    let i = len.checked_sub(i).ok_or(Error::OutOfBounds)?;

                    let real_index = s.char_indices().chain(Some((byte_len, '\x00'))).nth(i).ok_or(Error::OutOfBounds)?.0;
                    let right = s.split_off(real_index);
                    state.push(Str(s));
                    state.push(Str(right));
                }
                _ => return Err(Error::InvalidSplitArg)
            }
        }
        Get => {
            let i = match state.pop()? {
                Num(n) => n,
                _ => return Err(Error::InvalidGetArg)
            } as usize;

            match state.pop()?.flatten() {
                Block(n, mut b) => {
                    debug_assert_eq!(n, 1, "value has been flattened");

                    let i = b.len().checked_sub(i+1).ok_or(Error::OutOfBounds)?;

                    let cmd = b.remove(i);
                    state.push(Block(1, b));
                    state.push(Block(1, vec![cmd]));
                }
                Str(mut s) => {
                    let len = s.chars().count();
                    let byte_len = s.len();

                    let i = len.checked_sub(i).ok_or(Error::OutOfBounds)?;

                    let real_index = s.char_indices().chain(Some((byte_len, '\x00'))).nth(i).ok_or(Error::OutOfBounds)?.0;
                    let right = s.split_off(real_index);

                    let c = s.pop().ok_or(Error::OutOfBounds)?.to_string();

                    s += &right;

                    state.push(Str(s));
                    state.push(Str(c));
                }
                _ => return Err(Error::InvalidGetArg)
            }
        }
        DupGet => {
            let i = match state.pop()? {
                Num(n) => n,
                _ => return Err(Error::InvalidGetArg)
            } as usize;

            let val = match state.peek()? {
                Block(n, b) => {
                    let len = *n as usize * b.len();
                    let i = len.checked_sub(i+1).ok_or(Error::OutOfBounds)?;

                    let real_index = i % b.len();

                    let cmd = b[real_index].clone();

                    Block(1, vec![cmd])
                }
                Str(s) => {
                    let c = s.chars().rev().nth(i).ok_or(Error::OutOfBounds)?;

                    Str(c.to_string())
                }
                _ => return Err(Error::InvalidGetArg)
            };

            state.push(val);
        }
        Move => match state.pop()? {
            Num(n) => {
                let elem = state.peek()?.clone();

                state.insert(n as usize, elem)?;
                state.pop()?;
            },
            _ => return Err(Error::InvalidMoveArg)
        }
        Grab => match state.pop()? {
            Num(n) => {
                let n_elem = state.take_nth(n as usize)?;

                state.push(n_elem);
            },
            _ => return Err(Error::InvalidGrabArg)
        }
        DupGrab => match state.pop()? {
            Num(n) => {
                let n_elem = state.nth(n as usize)?.clone();

                state.push(n_elem);
            },
            _ => return Err(Error::InvalidGrabArg)
        }
        Drop => {
            state.pop()?;
        }
        CastNum => state.last_mut()?.make_num(),
        Eq => binop(state, |a, b| a == b)?,
        Neq => binop(state, |a, b| a != b)?,
        Write => write!(io.o, "{}", state.pop()?)?,
        Print => write!(io.o, "{}\n", state.pop()?)?,
        Or => binop(state, ops::BitOr::bitor)?,
        And => binop(state, ops::BitAnd::bitand)?,
        Add => binop(state, ops::Add::add)?,
        Sub => binop(state, ops::Sub::sub)?,
        Mul => binop(state, ops::Mul::mul)?,
        Div => binop(state, ops::Div::div)?,
        Rem => binop(state, ops::Rem::rem)?
    }

    Ok(())
}
<commit_msg>Applying strings does nothing<commit_after>use std::fs::File;
use std::io::{Write, Read, BufRead, BufReader};

mod chars;
mod value;
mod cmd;
mod state;
mod err;

use chars::*;
use value::Value;
use value::Value::*;
use cmd::Command;
use cmd::Command::*;
pub use state::State;
pub use err::{Result, Error};

pub struct InOuter<W: Write, R: Read> {
    o: W,
    i: BufReader<R>,
}

impl<W: Write, R: Read> InOuter<W, R> {
    pub fn new(o: W, i: R) -> Self {
        InOuter {
            o,
            i: BufReader::new(i),
        }
    }
    pub fn extract(self) -> (W, R) {
        let InOuter{i, o} = self;
        (o, i.into_inner())
    }
}

pub fn run_with_state<R, R2, W>(src: R, state: &mut State, io: &mut InOuter<W, R2>) -> Result<()>
where R: Read, R2: Read, W: Write {
    let mut buf = String::new();
    let mut ignoring_whitespace = false;

    for c in src.chars_iterator() {
        match c {
            Ok(c) => {
                if c.is_whitespace() && !ignoring_whitespace {
                    if !buf.is_empty() {
                        run_command(state, Command::from_str(&buf), io)?;
                        buf.clear();
                    }
                } else {
                    if c == '"' {
                        ignoring_whitespace = !ignoring_whitespace;
                    }
                    buf.push(c);
                }
            },
            Err(e) => return Err(Error::CharsError(e))
        }
    }

    Ok(())
}

fn binop<T: Into<Value>, F: FnOnce(Value, Value) -> T>(s: &mut State, f: F) -> Result<()> {
    let b = s.pop()?;
    let a = s.pop()?;

    s.push(f(a, b).into());
    Ok(())
}

use std::ops;
use std::mem::replace;

fn run_command<W: Write, R: Read>(state: &mut State, cmd: Command, io: &mut InOuter<W, R>) -> Result<()> {
    if cfg!(feature = "debug") {
        println!("{f}  {indent}{:?}: {:?}", cmd, state.stack(),
            f = if cmd == BeginBlock {"\n"}else{""},
            indent = "    ".repeat((state.block_nesting as usize)
            .saturating_sub(if cmd == EndBlock {1}else{0})),
        );
    }

    match cmd {
        EndBlock => match state.block_nesting {
            0 => return Err(Error::NoBlockStarted),
            1 => {
                state.block_nesting = 0;

                let t = replace(&mut state.temp, Vec::new());
                state.push(Block(1, t));
            }
            _ => {
                state.block_nesting -= 1;
                state.temp.push(EndBlock);
            }
        }
        BeginBlock => {
            state.block_nesting += 1;
            if state.block_nesting > 1 {
                state.temp.push(BeginBlock);
            }
        }
        ref cmd if state.block_nesting > 0 => state.temp.push(cmd.clone()),
        Value(s) => if s.starts_with('"') {
            state.push(Str(s[1..s.len()-1].to_owned()));
        } else if let Ok(n) = s.parse::<f64>() {
            state.push(Num(n));
        } else {
            let to_push;
            if let Some(v) = state.get_var(&s) {
                to_push = v.clone();
            } else {
                to_push = Variable(s);
            }
            state.push(to_push);
        }
        EmptyBlock => state.push(Block(1, Vec::new())),
        Include => {
            match state.pop()? {
                Str(s) => {
                    let file = File::open(s)?;
                    run_with_state(file, state, io)?;
                }
                _ => return Err(Error::InvalidIncludeArg)
            }
        }
        True => state.push(Num(1.)),
        False => state.push(Num(0.)),
        NullVal => state.push(Value::Null),
        Size => {
            let size = state.stack().len() as f64;
            state.push(Num(size))
        }
        Length => {
            let to_push = match *state.peek()? {
                Block(n, ref b) => Num((n as usize * b.len()) as f64),
                Str(ref s) => Num(s.chars().count() as f64),
                _ => Null
            };
            state.push(to_push);
        }
        Dup => {
            let dup = state.peek()?.clone();
            state.push(dup);
        }
        Not => {
            let a = state.pop()?;
            state.push(!a);
        }
        If => {
            let when_false = state.pop()?;
            let when_true = state.pop()?;
            let condition = state.pop()?;

            state.push(if condition.as_bool() {
                when_true
            } else {
                when_false
            });
        }
        Assign => {
            match (state.pop()?, state.pop()?) {
                (Variable(_), Variable(_)) => return Err(Error::InvalidAssignArg),
                (Variable(h), v) | (v, Variable(h)) => state.add_var(h, v),
                _ => return Err(Error::InvalidAssignArg),
            }
        }
        ApplyFunction => {
            match state.pop()? {
                Block(n, b) => {
                    for _ in 0..n {
                        for cmd in &b {
                            run_command(state, cmd.clone(), io)?;
                        }
                    }
                }
                s @ Str(_) => state.push(s),
                _ => return Err(Error::InvalidApplyArg)
            }
        }
        Read => {
            let mut line = String::new();
            io.i.read_line(&mut line)?;
            line = line.trim_right().to_owned();
            state.push(Str(line));
        }
        Swap => {
            let a = state.pop()?;
            let b = state.pop()?;
            state.push(a);
            state.push(b);
        }
        Split => {
            let i = match state.pop()? {
                Num(n) => n,
                _ => return Err(Error::InvalidSplitArg)
            } as usize;

            match state.pop()?.flatten() {
                Block(n, mut b) => {
                    debug_assert_eq!(n, 1, "value has been flattened");

                    let i = b.len().checked_sub(i).ok_or(Error::OutOfBounds)?;

                    let right = b.split_off(i);
                    state.push(Block(1, b));
                    state.push(Block(1, right));
                }
                Str(mut s) => {
                    let len = s.chars().count();
                    let byte_len = s.len();

                    let i = len.checked_sub(i).ok_or(Error::OutOfBounds)?;

                    let real_index = s.char_indices().chain(Some((byte_len, '\x00'))).nth(i).ok_or(Error::OutOfBounds)?.0;
                    let right = s.split_off(real_index);
                    state.push(Str(s));
                    state.push(Str(right));
                }
                _ => return Err(Error::InvalidSplitArg)
            }
        }
        Get => {
            let i = match state.pop()? {
                Num(n) => n,
                _ => return Err(Error::InvalidGetArg)
            } as usize;

            match state.pop()?.flatten() {
                Block(n, mut b) => {
                    debug_assert_eq!(n, 1, "value has been flattened");

                    let i = b.len().checked_sub(i+1).ok_or(Error::OutOfBounds)?;

                    let cmd = b.remove(i);
                    state.push(Block(1, b));
                    state.push(Block(1, vec![cmd]));
                }
                Str(mut s) => {
                    let len = s.chars().count();
                    let byte_len = s.len();

                    let i = len.checked_sub(i).ok_or(Error::OutOfBounds)?;

                    let real_index = s.char_indices().chain(Some((byte_len, '\x00'))).nth(i).ok_or(Error::OutOfBounds)?.0;
                    let right = s.split_off(real_index);

                    let c = s.pop().ok_or(Error::OutOfBounds)?.to_string();

                    s += &right;

                    state.push(Str(s));
                    state.push(Str(c));
                }
                _ => return Err(Error::InvalidGetArg)
            }
        }
        DupGet => {
            let i = match state.pop()? {
                Num(n) => n,
                _ => return Err(Error::InvalidGetArg)
            } as usize;

            let val = match state.peek()? {
                Block(n, b) => {
                    let len = *n as usize * b.len();
                    let i = len.checked_sub(i+1).ok_or(Error::OutOfBounds)?;

                    let real_index = i % b.len();

                    let cmd = b[real_index].clone();

                    Block(1, vec![cmd])
                }
                Str(s) => {
                    let c = s.chars().rev().nth(i).ok_or(Error::OutOfBounds)?;

                    Str(c.to_string())
                }
                _ => return Err(Error::InvalidGetArg)
            };

            state.push(val);
        }
        Move => match state.pop()? {
            Num(n) => {
                let elem = state.peek()?.clone();

                state.insert(n as usize, elem)?;
                state.pop()?;
            },
            _ => return Err(Error::InvalidMoveArg)
        }
        Grab => match state.pop()? {
            Num(n) => {
                let n_elem = state.take_nth(n as usize)?;

                state.push(n_elem);
            },
            _ => return Err(Error::InvalidGrabArg)
        }
        DupGrab => match state.pop()? {
            Num(n) => {
                let n_elem = state.nth(n as usize)?.clone();

                state.push(n_elem);
            },
            _ => return Err(Error::InvalidGrabArg)
        }
        Drop => {
            state.pop()?;
        }
        CastNum => state.last_mut()?.make_num(),
        Eq => binop(state, |a, b| a == b)?,
        Neq => binop(state, |a, b| a != b)?,
        Write => write!(io.o, "{}", state.pop()?)?,
        Print => write!(io.o, "{}\n", state.pop()?)?,
        Or => binop(state, ops::BitOr::bitor)?,
        And => binop(state, ops::BitAnd::bitand)?,
        Add => binop(state, ops::Add::add)?,
        Sub => binop(state, ops::Sub::sub)?,
        Mul => binop(state, ops::Mul::mul)?,
        Div => binop(state, ops::Div::div)?,
        Rem => binop(state, ops::Rem::rem)?
    }

    Ok(())
}
<|endoftext|>


<commit_before>pub mod num;

#[cfg(test)]
mod tests;
<commit_msg>Only export the Checked struct<commit_after>mod num;
pub use num::Checked;

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(core)]
#![feature(debug_builders)]
extern crate libc;

pub mod instruction;
pub mod constants;
pub mod ffi;
pub mod capstone;

pub use instruction::*;
pub use constants::*;

pub use capstone::Capstone;

use std::ptr;

// bindgen by default used this type name everywhere, it is easier to leave it alone.
#[allow(non_camel_case_types)]
pub type csh = libc::size_t;
<commit_msg>Update docstring<commit_after>#![feature(libc)]
#![feature(core)]
#![feature(debug_builders)]
extern crate libc;

pub mod instruction;
pub mod constants;
pub mod ffi;
pub mod capstone;

pub use instruction::*;
pub use constants::*;

pub use capstone::Capstone;

use std::ptr;

/// An opaque reference to a capstone engine.
///
/// bindgen by default used this type name everywhere, so it is easier to leave it with a confusing
/// name.
///
/// It should not be exported, rust's new visibility rules make tackling this not immediately
/// obvious
#[allow(non_camel_case_types)]
pub type csh = libc::size_t;
<|endoftext|>


<commit_before>//! Compile-time assertions to ensure that invariants are met.
//!
//! # Usage
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! static_assertions = "0.1"
//! ```
//!
//! and this to your crate root:
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! # fn main() {}
//! ```
//!
//! # Assert Equal Size
//!
//! When performing operations such as pointer casts or dealing with [`usize`]
//! versus [`u64`] versus [`u32`], the size of your types matter. This is where
//! [`assert_eq_size`] comes into play. Types provided as arguments to
//! [`assert_eq_size`] are ensured to be the same size at compile-time. If the
//! types differ in size, the code will fail to compile.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! // Can be declared outside of a function if labeled
//! assert_eq_size!(bytes; (u8, u8), u16);
//!
//! // Fails to compile (same label):
//! // assert_eq_size!(bytes; u8, u8);
//!
//! fn main() {
//!     assert_eq_size!([u8; 4], (u16, u16), u32);
//!
//!     // Produces a compilation failure:
//!     // assert_eq_size!(u32, u8);
//! }
//! ```
//!
//! Similar to [`assert_eq_size`], there is [`assert_eq_size_val`]. Instead of
//! specifying types to compare, values' sizes can be directly compared against
//! each other.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! let x = 42u8;
//! let y = true;
//!
//! assert_eq_size_val!(x, y);
//! # }
//! ```
//! [`assert_eq_size_val`] doesn't consume its arguments and thus works for
//! non-[`Clone`]able values.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! struct Buffer([u8; 256]);
//!
//! let buf = Buffer([0; 256]);
//! let val = [0u64; 32];
//!
//! assert_eq_size_val!(buf, val);
//!
//! // `buf` and `val` can be used here
//! # }
//! ```
//!
//! Rather than dereference a pointer to achieve the same effect as
//! [`assert_eq_size_val`], there is also the option of [`assert_eq_size_ptr`].
//!
//! # Assert Constant Expression
//!
//! Constant expressions can be ensured to have certain properties via
//! [`const_assert`]. If the expression evaluates to `false`, the file will fail
//! to compile. This is synonymous to [`static_assert` in C++][static_assert].
//!
//! As a [limitation](#limitations), a unique label is required if the macro is
//! used outside of a function.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! const NUM: usize = 32;
//!
//! const_assert!(NUM * NUM == 1024);
//! # }
//! ```
//!
//! As a shorthand for `const_assert!(a == b)`, there's [`const_assert_eq`]:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! const TWO: usize = 2;
//! const_assert_eq!(two; TWO * TWO, TWO + TWO, 4);
//!
//! // Produces a compilation failure:
//! // const_assert_eq!(two; TWO, TWO);
//!
//! fn main() {
//!     const NUM: usize = 32;
//!     const_assert_eq!(NUM + NUM, 64);
//! }
//! ```
//!
//! # Limitations
//!
//! Due to implementation details, [`assert_eq_size`], [`const_assert`], and
//! [`const_assert_eq`] can only be used normally from within the context of a
//! function.
//!
//! To use these macros in other contexts, a unique label must be provided.
//!
//! [crate]: https://crates.io/crates/static_assertions
//! [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
//! [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
//! [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html
//! [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html
//! [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html
//! [`assert_eq_size_val`]: macro.assert_eq_size_val.html
//! [`assert_eq_size_ptr`]: macro.assert_eq_size_ptr.html
//! [`assert_eq_size`]: macro.assert_eq_size.html
//! [`const_assert`]: macro.const_assert.html
//! [`const_assert_eq`]: macro.const_assert_eq.html

#![no_std]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts at compile-time that the types have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// struct Byte(u8);
///
/// assert_eq_size!(pair; (u16, u16), [u16; 2], [u8; 4]);
///
/// // Fails to compile (same label):
/// // assert_eq_size!(pair; u8, u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
///
///     // Produces a compilation failure:
///     // assert_eq_size!(Byte, u16);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::mem::{forget, transmute, uninitialized};
            $(forget::<$xs>(transmute(uninitialized::<$x>()));)+
        }
    };
    ($label:ident; $x:ty, $($xs:ty),+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_eq_size!($x, $($xs),+) }
    };
}

/// Asserts at compile-time that the values pointed to have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// fn operation(x: &(u32, u32), y: &[u16; 4]) {
///     assert_eq_size_ptr!(x, y);
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! assert_eq_size_ptr {
    ($x:expr, $($xs:expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read($x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+
            mem::forget(copy);
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
///
/// // Fails to compile:
/// // assert_eq_size_val!(x, 0u32);
/// # }
/// ```
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+) => {
        assert_eq_size_ptr!(&$x, $(&$xs),+);
    }
}

/// Asserts at compile-time that the constant expression evaluates to `true`.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// const_assert!(2 + 2 == 4);
///
/// const FIVE: usize = 5;
/// const_assert!(FIVE - FIVE == 0);
///
/// // Produces a compilation failure:
/// // const_assert!(1 >= 2);
/// # }
/// ```
#[macro_export]
macro_rules! const_assert {
    ($($xs:expr),+) => {
        let _ = [(); 0 - (!($($xs)&&+) as usize)];
    };
    ($label:ident; $($xs:expr),+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { const_assert!($($xs),+); }
    };
}

/// Asserts at compile-time that the constants are equal in value.
#[macro_export]
macro_rules! const_assert_eq {
    ($x:expr, $($xs:expr),+) => {
        const_assert!($($x == $xs),+);
    };
    ($label:ident; $x:expr, $($xs:expr),+) => {
        const_assert!($label; $($x == $xs),+);
    };
}
<commit_msg>Link limitations GitHub issue in documentation<commit_after>//! Compile-time assertions to ensure that invariants are met.
//!
//! # Usage
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! static_assertions = "0.1"
//! ```
//!
//! and this to your crate root:
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! # fn main() {}
//! ```
//!
//! # Assert Equal Size
//!
//! When performing operations such as pointer casts or dealing with [`usize`]
//! versus [`u64`] versus [`u32`], the size of your types matter. This is where
//! [`assert_eq_size`] comes into play. Types provided as arguments to
//! [`assert_eq_size`] are ensured to be the same size at compile-time. If the
//! types differ in size, the code will fail to compile.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! // Can be declared outside of a function if labeled
//! assert_eq_size!(bytes; (u8, u8), u16);
//!
//! // Fails to compile (same label):
//! // assert_eq_size!(bytes; u8, u8);
//!
//! fn main() {
//!     assert_eq_size!([u8; 4], (u16, u16), u32);
//!
//!     // Produces a compilation failure:
//!     // assert_eq_size!(u32, u8);
//! }
//! ```
//!
//! Similar to [`assert_eq_size`], there is [`assert_eq_size_val`]. Instead of
//! specifying types to compare, values' sizes can be directly compared against
//! each other.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! let x = 42u8;
//! let y = true;
//!
//! assert_eq_size_val!(x, y);
//! # }
//! ```
//! [`assert_eq_size_val`] doesn't consume its arguments and thus works for
//! non-[`Clone`]able values.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! struct Buffer([u8; 256]);
//!
//! let buf = Buffer([0; 256]);
//! let val = [0u64; 32];
//!
//! assert_eq_size_val!(buf, val);
//!
//! // `buf` and `val` can be used here
//! # }
//! ```
//!
//! Rather than dereference a pointer to achieve the same effect as
//! [`assert_eq_size_val`], there is also the option of [`assert_eq_size_ptr`].
//!
//! # Assert Constant Expression
//!
//! Constant expressions can be ensured to have certain properties via
//! [`const_assert`]. If the expression evaluates to `false`, the file will fail
//! to compile. This is synonymous to [`static_assert` in C++][static_assert].
//!
//! As a [limitation](#limitations), a unique label is required if the macro is
//! used outside of a function.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! const NUM: usize = 32;
//!
//! const_assert!(NUM * NUM == 1024);
//! # }
//! ```
//!
//! As a shorthand for `const_assert!(a == b)`, there's [`const_assert_eq`]:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! const TWO: usize = 2;
//! const_assert_eq!(two; TWO * TWO, TWO + TWO, 4);
//!
//! // Produces a compilation failure:
//! // const_assert_eq!(two; TWO, TWO);
//!
//! fn main() {
//!     const NUM: usize = 32;
//!     const_assert_eq!(NUM + NUM, 64);
//! }
//! ```
//!
//! # Limitations
//!
//! Due to implementation details, [`assert_eq_size`], [`const_assert`], and
//! [`const_assert_eq`] can only be used normally from within the context of a
//! function.
//!
//! To use these macros in other contexts, a unique label must be provided.
//!
//! If you want to read up about this and provide feedback, see
//! [the related issue on GitHub][issue1].
//!
//! [issue1]: https://github.com/nvzqz/static-assertions-rs/issues/1
//! [crate]: https://crates.io/crates/static_assertions
//! [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
//! [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
//! [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html
//! [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html
//! [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html
//! [`assert_eq_size_val`]: macro.assert_eq_size_val.html
//! [`assert_eq_size_ptr`]: macro.assert_eq_size_ptr.html
//! [`assert_eq_size`]: macro.assert_eq_size.html
//! [`const_assert`]: macro.const_assert.html
//! [`const_assert_eq`]: macro.const_assert_eq.html

#![no_std]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts at compile-time that the types have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// struct Byte(u8);
///
/// assert_eq_size!(pair; (u16, u16), [u16; 2], [u8; 4]);
///
/// // Fails to compile (same label):
/// // assert_eq_size!(pair; u8, u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
///
///     // Produces a compilation failure:
///     // assert_eq_size!(Byte, u16);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::mem::{forget, transmute, uninitialized};
            $(forget::<$xs>(transmute(uninitialized::<$x>()));)+
        }
    };
    ($label:ident; $x:ty, $($xs:ty),+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_eq_size!($x, $($xs),+) }
    };
}

/// Asserts at compile-time that the values pointed to have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// fn operation(x: &(u32, u32), y: &[u16; 4]) {
///     assert_eq_size_ptr!(x, y);
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! assert_eq_size_ptr {
    ($x:expr, $($xs:expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read($x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+
            mem::forget(copy);
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
///
/// // Fails to compile:
/// // assert_eq_size_val!(x, 0u32);
/// # }
/// ```
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+) => {
        assert_eq_size_ptr!(&$x, $(&$xs),+);
    }
}

/// Asserts at compile-time that the constant expression evaluates to `true`.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// const_assert!(2 + 2 == 4);
///
/// const FIVE: usize = 5;
/// const_assert!(FIVE - FIVE == 0);
///
/// // Produces a compilation failure:
/// // const_assert!(1 >= 2);
/// # }
/// ```
#[macro_export]
macro_rules! const_assert {
    ($($xs:expr),+) => {
        let _ = [(); 0 - (!($($xs)&&+) as usize)];
    };
    ($label:ident; $($xs:expr),+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { const_assert!($($xs),+); }
    };
}

/// Asserts at compile-time that the constants are equal in value.
#[macro_export]
macro_rules! const_assert_eq {
    ($x:expr, $($xs:expr),+) => {
        const_assert!($($x == $xs),+);
    };
    ($label:ident; $x:expr, $($xs:expr),+) => {
        const_assert!($label; $($x == $xs),+);
    };
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_name = "portaudio"]
#![feature(phase, unsafe_destructor)]
#![warn(missing_docs)]

//! PortAudio bindings for Rust
//!
//! # Example
//!
//! ```
//! fn demo() -> portaudio::pa::PaResult
//! {
//!     let stream = try!(portaudio::stream::Stream::open_default(
//!                           0, // input channels
//!                           1, // output channels
//!                           44100.0, // sample rate
//!                           portaudio::stream::FRAMES_PER_BUFFER_UNSPECIFIED,
//!                           None // no callback
//!                      ));
//!
//!     try!(stream.start());
//!
//!     let mut phase = 0.0f32;
//!     let mut buffer = Vec::with_capacity(44100);
//!     for _i in range(0u, 44100)
//!     {
//!         // Small amplitude such that the test does not produce sound
//!         buffer.push(phase * 0.001);
//!
//!         phase += 0.03;
//!         if phase > 1.0 { phase -= 2.0; }
//!     }
//!
//!     try!(stream.write(buffer.as_slice()));
//!
//!     Ok(())
//! }
//!
//! portaudio::pa::initialize().unwrap();
//! println!("{}", demo());
//! portaudio::pa::terminate().unwrap();
//! ```

extern crate libc;
#[phase(plugin, link)] extern crate log;

pub mod stream;
pub mod pa;
pub mod hostapi;
pub mod device;

mod ll;
mod util;
<commit_msg>Added pub use for all in the pa mod<commit_after>#![crate_type = "lib"]
#![crate_name = "portaudio"]
#![feature(phase, unsafe_destructor)]
#![warn(missing_docs)]

//! PortAudio bindings for Rust
//!
//! # Example
//!
//! ```
//! fn demo() -> portaudio::PaResult
//! {
//!     let stream = try!(portaudio::stream::Stream::open_default(
//!                           0, // input channels
//!                           1, // output channels
//!                           44100.0, // sample rate
//!                           portaudio::stream::FRAMES_PER_BUFFER_UNSPECIFIED,
//!                           None // no callback
//!                      ));
//!
//!     try!(stream.start());
//!
//!     let mut phase = 0.0f32;
//!     let mut buffer = Vec::with_capacity(44100);
//!     for _i in range(0u, 44100)
//!     {
//!         // Small amplitude such that the test does not produce sound
//!         buffer.push(phase * 0.001);
//!
//!         phase += 0.03;
//!         if phase > 1.0 { phase -= 2.0; }
//!     }
//!
//!     try!(stream.write(buffer.as_slice()));
//!
//!     Ok(())
//! }
//!
//! portaudio::initialize().unwrap();
//! println!("{}", demo());
//! portaudio::terminate().unwrap();
//! ```

extern crate libc;
#[phase(plugin, link)] extern crate log;

pub use pa::{PaError, PaResult, initialize, terminate, version, version_text};

pub mod stream;
pub mod pa;
pub mod hostapi;
pub mod device;

mod ll;
mod util;
<|endoftext|>


<commit_before>#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#[cfg(feature = "printing")]
#[macro_use]
extern crate quote;

#[cfg(feature = "pretty")]
extern crate syntex_syntax as syntax;

#[cfg(feature = "parsing")]
extern crate unicode_xid;

#[cfg(feature = "parsing")]
#[macro_use]
mod nom;

#[cfg(feature = "parsing")]
#[macro_use]
mod helper;

#[cfg(feature = "parsing")]
mod escape;

mod attr;
pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem};

mod constant;
pub use constant::ConstExpr;

mod data;
pub use data::{Field, Variant, VariantData, Visibility};

#[cfg(feature = "full")]
mod expr;
#[cfg(feature = "full")]
pub use expr::{Arm, BindingMode, Block, BlockCheckMode, CaptureBy, Expr, FieldPat, Local,
               MacStmtStyle, Pat, RangeLimits, Stmt};

mod generics;
pub use generics::{Generics, Lifetime, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
                   WhereBoundPredicate, WhereClause, WherePredicate, WhereRegionPredicate};
#[cfg(feature = "printing")]
pub use generics::{ImplGenerics, TyGenerics};

#[cfg(feature = "full")]
mod krate;
#[cfg(feature = "full")]
pub use krate::Crate;

mod ident;
pub use ident::Ident;

#[cfg(feature = "full")]
mod item;
#[cfg(feature = "full")]
pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItemKind, ForeignItem, ForeignMod,
               ImplItem, ImplItemKind, ImplPolarity, Item, ItemKind, MethodSig, PathListItem,
               TraitItem, TraitItemKind, ViewPath};

mod lit;
pub use lit::{FloatTy, IntTy, Lit, StrStyle};

#[cfg(feature = "full")]
mod mac;
#[cfg(feature = "full")]
pub use mac::{BinOpToken, DelimToken, Delimited, Mac, Token, TokenTree};

mod macro_input;
pub use macro_input::{Body, MacroInput};

mod op;
pub use op::{BinOp, UnOp};

#[cfg(feature = "expand")]
mod registry;
#[cfg(feature = "expand")]
pub use registry::{CustomDerive, Expanded, Registry};

#[cfg(feature = "parsing")]
mod space;

mod ty;
pub use ty::{Abi, AngleBracketedParameterData, BareFnArg, BareFnTy, FunctionRetTy, MutTy,
             Mutability, ParenthesizedParameterData, Path, PathParameters, PathSegment,
             PolyTraitRef, QSelf, Ty, TypeBinding, Unsafety};

#[cfg(feature = "aster")]
pub mod aster;

#[cfg(feature = "visit")]
pub mod visit;

#[cfg(feature = "parsing")]
pub use parsing::*;

#[cfg(feature = "parsing")]
mod parsing {
    use super::*;
    use {generics, macro_input, space, ty};
    use nom::IResult;

    #[cfg(feature = "full")]
    use {expr, item, krate, mac};

    pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
        unwrap("macro input", macro_input::parsing::macro_input, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_crate(input: &str) -> Result<Crate, String> {
        unwrap("crate", krate::parsing::krate, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_item(input: &str) -> Result<Item, String> {
        unwrap("item", item::parsing::item, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_items(input: &str) -> Result<Vec<Item>, String> {
        unwrap("items", item::parsing::items, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_expr(input: &str) -> Result<Expr, String> {
        unwrap("expression", expr::parsing::expr, input)
    }

    pub fn parse_type(input: &str) -> Result<Ty, String> {
        unwrap("type", ty::parsing::ty, input)
    }

    pub fn parse_path(input: &str) -> Result<Path, String> {
        unwrap("path", ty::parsing::path, input)
    }

    pub fn parse_where_clause(input: &str) -> Result<WhereClause, String> {
        unwrap("where clause", generics::parsing::where_clause, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_token_trees(input: &str) -> Result<Vec<TokenTree>, String> {
        unwrap("token trees", mac::parsing::token_trees, input)
    }

    fn unwrap<T>(name: &'static str,
                 f: fn(&str) -> IResult<&str, T>,
                 input: &str)
                 -> Result<T, String> {
        match f(input) {
            IResult::Done(mut rest, t) => {
                rest = space::skip_whitespace(rest);
                if rest.is_empty() {
                    Ok(t)
                } else if rest.len() == input.len() {
                    // parsed nothing
                    Err(format!("failed to parse {}: {:?}", name, rest))
                } else {
                    Err(format!("failed to parse tokens after {}: {:?}", name, rest))
                }
            }
            IResult::Error => Err(format!("failed to parse {}: {:?}", name, input)),
        }
    }
}
<commit_msg>re-export ExprKind<commit_after>#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#[cfg(feature = "printing")]
#[macro_use]
extern crate quote;

#[cfg(feature = "pretty")]
extern crate syntex_syntax as syntax;

#[cfg(feature = "parsing")]
extern crate unicode_xid;

#[cfg(feature = "parsing")]
#[macro_use]
mod nom;

#[cfg(feature = "parsing")]
#[macro_use]
mod helper;

#[cfg(feature = "parsing")]
mod escape;

mod attr;
pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem};

mod constant;
pub use constant::ConstExpr;

mod data;
pub use data::{Field, Variant, VariantData, Visibility};

#[cfg(feature = "full")]
mod expr;
#[cfg(feature = "full")]
pub use expr::{Arm, BindingMode, Block, BlockCheckMode, CaptureBy, Expr, ExprKind, FieldPat, Local,
               MacStmtStyle, Pat, RangeLimits, Stmt};

mod generics;
pub use generics::{Generics, Lifetime, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
                   WhereBoundPredicate, WhereClause, WherePredicate, WhereRegionPredicate};
#[cfg(feature = "printing")]
pub use generics::{ImplGenerics, TyGenerics};

#[cfg(feature = "full")]
mod krate;
#[cfg(feature = "full")]
pub use krate::Crate;

mod ident;
pub use ident::Ident;

#[cfg(feature = "full")]
mod item;
#[cfg(feature = "full")]
pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItemKind, ForeignItem, ForeignMod,
               ImplItem, ImplItemKind, ImplPolarity, Item, ItemKind, MethodSig, PathListItem,
               TraitItem, TraitItemKind, ViewPath};

mod lit;
pub use lit::{FloatTy, IntTy, Lit, StrStyle};

#[cfg(feature = "full")]
mod mac;
#[cfg(feature = "full")]
pub use mac::{BinOpToken, DelimToken, Delimited, Mac, Token, TokenTree};

mod macro_input;
pub use macro_input::{Body, MacroInput};

mod op;
pub use op::{BinOp, UnOp};

#[cfg(feature = "expand")]
mod registry;
#[cfg(feature = "expand")]
pub use registry::{CustomDerive, Expanded, Registry};

#[cfg(feature = "parsing")]
mod space;

mod ty;
pub use ty::{Abi, AngleBracketedParameterData, BareFnArg, BareFnTy, FunctionRetTy, MutTy,
             Mutability, ParenthesizedParameterData, Path, PathParameters, PathSegment,
             PolyTraitRef, QSelf, Ty, TypeBinding, Unsafety};

#[cfg(feature = "aster")]
pub mod aster;

#[cfg(feature = "visit")]
pub mod visit;

#[cfg(feature = "parsing")]
pub use parsing::*;

#[cfg(feature = "parsing")]
mod parsing {
    use super::*;
    use {generics, macro_input, space, ty};
    use nom::IResult;

    #[cfg(feature = "full")]
    use {expr, item, krate, mac};

    pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
        unwrap("macro input", macro_input::parsing::macro_input, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_crate(input: &str) -> Result<Crate, String> {
        unwrap("crate", krate::parsing::krate, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_item(input: &str) -> Result<Item, String> {
        unwrap("item", item::parsing::item, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_items(input: &str) -> Result<Vec<Item>, String> {
        unwrap("items", item::parsing::items, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_expr(input: &str) -> Result<Expr, String> {
        unwrap("expression", expr::parsing::expr, input)
    }

    pub fn parse_type(input: &str) -> Result<Ty, String> {
        unwrap("type", ty::parsing::ty, input)
    }

    pub fn parse_path(input: &str) -> Result<Path, String> {
        unwrap("path", ty::parsing::path, input)
    }

    pub fn parse_where_clause(input: &str) -> Result<WhereClause, String> {
        unwrap("where clause", generics::parsing::where_clause, input)
    }

    #[cfg(feature = "full")]
    pub fn parse_token_trees(input: &str) -> Result<Vec<TokenTree>, String> {
        unwrap("token trees", mac::parsing::token_trees, input)
    }

    fn unwrap<T>(name: &'static str,
                 f: fn(&str) -> IResult<&str, T>,
                 input: &str)
                 -> Result<T, String> {
        match f(input) {
            IResult::Done(mut rest, t) => {
                rest = space::skip_whitespace(rest);
                if rest.is_empty() {
                    Ok(t)
                } else if rest.len() == input.len() {
                    // parsed nothing
                    Err(format!("failed to parse {}: {:?}", name, rest))
                } else {
                    Err(format!("failed to parse tokens after {}: {:?}", name, rest))
                }
            }
            IResult::Error => Err(format!("failed to parse {}: {:?}", name, input)),
        }
    }
}
<|endoftext|>