<commit_before>//! This module is UNSTABLE, the reason is - recently added.

use std::convert::From;
use std::io::{self, Read, BufRead};
use std::str::{from_utf8, Utf8Error};

use super::{read_marker};
use super::{
    ReadError,
    MarkerReadError,
};
use super::{BigEndianRead};

use super::super::init::Marker;
use super::super::value::{Integer, ValueRef};

trait USizeCast {
    fn from(v: Self) -> Option<usize> where Self: Sized;
}

impl USizeCast for u8 {
    fn from(v: u8) -> Option<usize> {
        // Impossible to panic, since u8 always fits in usize.
        Some(v as usize)
    }
}

impl USizeCast for u16 {
    fn from(v: u16) -> Option<usize> {
        // TODO: This can overflow on 8-bit systems.
        Some(v as usize)
    }
}

impl USizeCast for u32 {
    fn from(v: u32) -> Option<usize> {
        // TODO: This can overflow on 8- and 16-bit systems.
        Some(v as usize)
    }
}

// TODO: Display trait.
#[derive(Debug)]
pub enum Error<'r> {
    /// Failed to fill the internal reader buffer.
    ///
    /// RMP tries to obtain the buffer at the beginning of read operation using `read_buf` function.
    ///
    /// According to the Rust documentation, `fill_buf` function will return an I/O error if the
    /// underlying reader was read, but returned an error.
    InvalidBufferFill(io::Error),
    /// Failed to read the type marker value.
    InvalidMarkerRead(ReadError),
    /// Failed to read string/array/map size.
    InvalidLengthRead(ReadError),
    /// Failed to read packed non-marker data.
    InvalidDataRead(ReadError),
    /// Failed to cast the length read to machine size.
    InvalidLengthSize,
    /// Failed to interpret a byte slice as a UTF-8 string.
    ///
    /// Contains untouched bytearray with the underlying decoding error.
    InvalidUtf8(&'r [u8], Utf8Error),
    /// Failed to read ext type.
    InvalidExtTypeRead(ReadError),
}

impl<'r> From<MarkerReadError> for Error<'r> {
    fn from(err: MarkerReadError) -> Error<'r> {
        Error::InvalidMarkerRead(From::from(err))
    }
}

fn read_int<D>(mut rd: &[u8]) -> Result<D, Error>
    where D: BigEndianRead
{
    D::read(&mut rd).map_err(|err| Error::InvalidDataRead(From::from(err)))
}

fn read_length<R, D>(rd: &mut R) -> Result<D, ReadError>
    where R: Read,
          D: BigEndianRead
{
    D::read(rd).map_err(From::from)
}

fn read_str(buf: &[u8], len: usize) -> Result<&str, Error> {
    let buf = try!(read_bin(buf, len));

    // Try to decode sliced buffer as UTF-8.
    let res = try!(from_utf8(buf).map_err(|err| Error::InvalidUtf8(buf, err)));

    Ok(res)
}

fn read_bin(buf: &[u8], len: usize) -> Result<&[u8], Error> {
    if len > buf.len() {
        return Err(Error::InvalidDataRead(ReadError::UnexpectedEOF));
    }

    // Take a slice.
    let buf = &buf[..len];

    Ok(buf)
}

// Helper function that reads a single byte from the given `Read` and interpret it as an Ext type.
fn read_ext_type<R>(rd: &mut R) -> Result<i8, ReadError>
    where R: Read
{
    i8::read(rd).map_err(From::from)
}

fn read_ext(mut buf: &[u8], len: usize) -> Result<(i8, &[u8]), Error> {
    let ty  = try!(read_ext_type(&mut buf).map_err(|err| Error::InvalidExtTypeRead(err)));
    let buf = try!(read_bin(buf, len));

    Ok((ty, buf))
}

#[inline]
fn read_str_value<U>(buf: &[u8], len: U) -> Result<ValueRef, Error>
    where U: USizeCast
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_str(buf, len));

    Ok(ValueRef::String(res))
}

#[inline]
fn read_bin_value<U>(buf: &[u8], len: U) -> Result<ValueRef, Error>
    where U: USizeCast
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_bin(buf, len));

    Ok(ValueRef::Binary(res))
}

#[inline]
fn read_ext_value<U>(mut buf: &[u8], len: U) -> Result<ValueRef, Error>
    where U: USizeCast
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let (ty, buf) = try!(read_ext(&mut buf, len));

    Ok(ValueRef::Ext(ty, buf))
}

fn read_array(buf: &[u8], len: usize) -> Result<(Vec<ValueRef>, usize), Error> {
    let mut vec = Vec::with_capacity(len);
    let mut pos = 0;

    for _ in 0..len {
        let (val, num) = try!(read_value_ref_impl(&buf[pos..]));
        pos += num;
        vec.push(val);
    }

    Ok((vec, pos))
}

fn read_map(buf: &[u8], len: usize) -> Result<(Vec<(ValueRef, ValueRef)>, usize), Error> {
    let mut vec = Vec::with_capacity(len);
    let mut pos = 0;

    for _ in 0..len {
        let (key, num) = try!(read_value_ref_impl(&buf[pos..]));
        pos += num;

        let (val, num) = try!(read_value_ref_impl(&buf[pos..]));
        pos += num;

        vec.push((key, val));
    }

    Ok((vec, pos))
}

// TODO: Make more generic for [u8], Vec<u8>, Cursor<&[u8]>, Cursor<Vec<u8>>, ... all wrappers,
// where get_ref() -> &[u8].
// TODO: Get rid of manual counting bytes number consumed;
fn read_value_ref_impl(buf: &[u8]) -> Result<(ValueRef, usize), Error> {
    let mut buf = buf;
    let mut pos = 0usize;

    // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
    // 1 byte from the `buf`, not from the `rd`.
    let marker = try!(read_marker(&mut buf));
    pos += 1;

    let val = match marker {
        Marker::PositiveFixnum(val) => {
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U8 => {
            let val: u8 = try!(read_int(buf));
            pos += 1;
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U16 => {
            let val: u16 = try!(read_int(buf));
            pos += 2;
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U32 => {
            let val: u32 = try!(read_int(buf));
            pos += 4;
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U64 => {
            let val: u64 = try!(read_int(buf));
            pos += 8;
            ValueRef::Integer(Integer::U64(val))
        }
        Marker::NegativeFixnum(val) => {
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I8 => {
            let val: i8 = try!(read_int(buf));
            pos += 1;
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I16 => {
            let val: i16 = try!(read_int(buf));
            pos += 2;
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I32 => {
            let val: i32 = try!(read_int(buf));
            pos += 4;
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I64 => {
            let val: i64 = try!(read_int(buf));
            pos += 8;
            ValueRef::Integer(Integer::I64(val))
        }
        Marker::FixedString(len) => {
            pos += len as usize;
            try!(read_str_value(buf, len))
        }
        Marker::Str8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 1 + len as usize;
            try!(read_str_value(buf, len))
        }
        Marker::Str16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 2 + len as usize;
            try!(read_str_value(buf, len))
        }
        Marker::Str32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 4 + len as usize;
            try!(read_str_value(buf, len))
        }
        Marker::Bin8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 1 + len as usize;
            try!(read_bin_value(buf, len))
        }
        Marker::Bin16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 2 + len as usize;
            try!(read_bin_value(buf, len))
        }
        Marker::Bin32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 4 + len as usize;
            try!(read_bin_value(buf, len))
        }
        Marker::FixedArray(len) => {
            let len = len as usize;
            let (vec, bytes) = try!(read_array(&mut buf, len));
            pos += bytes;
            ValueRef::Array(vec)
        }
        Marker::Array16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            let len = len as usize;
            let (vec, bytes) = try!(read_array(&mut buf, len));
            pos += bytes;
            ValueRef::Array(vec)
        }
        Marker::Array32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            let len = len as usize;
            let (vec, bytes) = try!(read_array(&mut buf, len));
            pos += bytes;
            ValueRef::Array(vec)
        }
        Marker::FixedMap(len) => {
            let len = len as usize;
            let (map, bytes) = try!(read_map(&mut buf, len));
            pos += bytes;
            ValueRef::Map(map)
        }
        Marker::Map16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            let len = len as usize; // TODO: Possible overflow.
            let (map, bytes) = try!(read_map(&mut buf, len));
            pos += 2 + bytes;
            ValueRef::Map(map)
        }
        Marker::Map32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            let len = len as usize; // TODO: Possible overflow.
            let (map, bytes) = try!(read_map(&mut buf, len));
            pos += 4 + bytes;
            ValueRef::Map(map)
        }
        Marker::FixExt1 => {
            let len: u8 = 1;
            pos += 2;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::FixExt2 => {
            let len: u8 = 2;
            pos += 3;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::FixExt4 => {
            let len: u8 = 4;
            pos += 5;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::FixExt8 => {
            let len: u8 = 8;
            pos += 9;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::FixExt16 => {
            let len: u8 = 16;
            pos += 17;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::Ext8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 2 + len as usize;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::Ext16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 3 + len as usize;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::Ext32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 5 + len as usize;
            try!(read_ext_value(&mut buf, len))
        }
        _ => unimplemented!(),
    };

    Ok((val, pos as usize))
}

// NOTE: Consumes nothing from the given `BufRead` both on success and fail.
// TODO: Possible non-mut reference will be better.
pub fn read_value_ref<R>(rd: &mut R) -> Result<ValueRef, Error>
    where R: BufRead
{
    let buf = try!(rd.fill_buf().map_err(|err| Error::InvalidBufferFill(err)));
    let res = try!(read_value_ref_impl(buf)).0;
    Ok(res)
}

// TODO: Concepts: less code; more tests; fast refactoring after each test; no more than 5 min for
// each red-yellow-green.
<commit_msg>ValueRef: replace marker placeholder.<commit_after>//! This module is UNSTABLE, the reason is - recently added.

use std::convert::From;
use std::io::{self, Read, BufRead};
use std::str::{from_utf8, Utf8Error};

use super::{read_marker};
use super::{
    ReadError,
    MarkerReadError,
};
use super::{BigEndianRead};

use super::super::init::Marker;
use super::super::value::{Integer, ValueRef};

trait USizeCast {
    fn from(v: Self) -> Option<usize> where Self: Sized;
}

impl USizeCast for u8 {
    fn from(v: u8) -> Option<usize> {
        // Impossible to panic, since u8 always fits in usize.
        Some(v as usize)
    }
}

impl USizeCast for u16 {
    fn from(v: u16) -> Option<usize> {
        // TODO: This can overflow on 8-bit systems.
        Some(v as usize)
    }
}

impl USizeCast for u32 {
    fn from(v: u32) -> Option<usize> {
        // TODO: This can overflow on 8- and 16-bit systems.
        Some(v as usize)
    }
}

// TODO: Display trait.
#[derive(Debug)]
pub enum Error<'r> {
    /// Failed to fill the internal reader buffer.
    ///
    /// RMP tries to obtain the buffer at the beginning of read operation using `read_buf` function.
    ///
    /// According to the Rust documentation, `fill_buf` function will return an I/O error if the
    /// underlying reader was read, but returned an error.
    InvalidBufferFill(io::Error),
    /// Failed to read the type marker value.
    InvalidMarkerRead(ReadError),
    /// Failed to read string/array/map size.
    InvalidLengthRead(ReadError),
    /// Failed to read packed non-marker data.
    InvalidDataRead(ReadError),
    /// Failed to cast the length read to machine size.
    InvalidLengthSize,
    /// Failed to interpret a byte slice as a UTF-8 string.
    ///
    /// Contains untouched bytearray with the underlying decoding error.
    InvalidUtf8(&'r [u8], Utf8Error),
    /// Failed to read ext type.
    InvalidExtTypeRead(ReadError),
}

impl<'r> From<MarkerReadError> for Error<'r> {
    fn from(err: MarkerReadError) -> Error<'r> {
        Error::InvalidMarkerRead(From::from(err))
    }
}

fn read_int<D>(mut rd: &[u8]) -> Result<D, Error>
    where D: BigEndianRead
{
    D::read(&mut rd).map_err(|err| Error::InvalidDataRead(From::from(err)))
}

fn read_length<R, D>(rd: &mut R) -> Result<D, ReadError>
    where R: Read,
          D: BigEndianRead
{
    D::read(rd).map_err(From::from)
}

fn read_str(buf: &[u8], len: usize) -> Result<&str, Error> {
    let buf = try!(read_bin(buf, len));

    // Try to decode sliced buffer as UTF-8.
    let res = try!(from_utf8(buf).map_err(|err| Error::InvalidUtf8(buf, err)));

    Ok(res)
}

fn read_bin(buf: &[u8], len: usize) -> Result<&[u8], Error> {
    if len > buf.len() {
        return Err(Error::InvalidDataRead(ReadError::UnexpectedEOF));
    }

    // Take a slice.
    let buf = &buf[..len];

    Ok(buf)
}

// Helper function that reads a single byte from the given `Read` and interpret it as an Ext type.
fn read_ext_type<R>(rd: &mut R) -> Result<i8, ReadError>
    where R: Read
{
    i8::read(rd).map_err(From::from)
}

fn read_ext(mut buf: &[u8], len: usize) -> Result<(i8, &[u8]), Error> {
    let ty  = try!(read_ext_type(&mut buf).map_err(|err| Error::InvalidExtTypeRead(err)));
    let buf = try!(read_bin(buf, len));

    Ok((ty, buf))
}

#[inline]
fn read_str_value<U>(buf: &[u8], len: U) -> Result<ValueRef, Error>
    where U: USizeCast
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_str(buf, len));

    Ok(ValueRef::String(res))
}

#[inline]
fn read_bin_value<U>(buf: &[u8], len: U) -> Result<ValueRef, Error>
    where U: USizeCast
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_bin(buf, len));

    Ok(ValueRef::Binary(res))
}

#[inline]
fn read_ext_value<U>(mut buf: &[u8], len: U) -> Result<ValueRef, Error>
    where U: USizeCast
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let (ty, buf) = try!(read_ext(&mut buf, len));

    Ok(ValueRef::Ext(ty, buf))
}

fn read_array(buf: &[u8], len: usize) -> Result<(Vec<ValueRef>, usize), Error> {
    let mut vec = Vec::with_capacity(len);
    let mut pos = 0;

    for _ in 0..len {
        let (val, num) = try!(read_value_ref_impl(&buf[pos..]));
        pos += num;
        vec.push(val);
    }

    Ok((vec, pos))
}

fn read_map(buf: &[u8], len: usize) -> Result<(Vec<(ValueRef, ValueRef)>, usize), Error> {
    let mut vec = Vec::with_capacity(len);
    let mut pos = 0;

    for _ in 0..len {
        let (key, num) = try!(read_value_ref_impl(&buf[pos..]));
        pos += num;

        let (val, num) = try!(read_value_ref_impl(&buf[pos..]));
        pos += num;

        vec.push((key, val));
    }

    Ok((vec, pos))
}

// TODO: Make more generic for [u8], Vec<u8>, Cursor<&[u8]>, Cursor<Vec<u8>>, ... all wrappers,
// where get_ref() -> &[u8].
// TODO: Get rid of manual counting bytes number consumed;
fn read_value_ref_impl(buf: &[u8]) -> Result<(ValueRef, usize), Error> {
    let mut buf = buf;
    let mut pos = 0usize;

    // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
    // 1 byte from the `buf`, not from the `rd`.
    let marker = try!(read_marker(&mut buf));
    pos += 1;

    let val = match marker {
        Marker::Null => {
            unimplemented!();
        }
        Marker::True => {
            unimplemented!();
        }
        Marker::False => {
            unimplemented!();
        }
        Marker::PositiveFixnum(val) => {
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U8 => {
            let val: u8 = try!(read_int(buf));
            pos += 1;
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U16 => {
            let val: u16 = try!(read_int(buf));
            pos += 2;
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U32 => {
            let val: u32 = try!(read_int(buf));
            pos += 4;
            ValueRef::Integer(Integer::U64(val as u64))
        }
        Marker::U64 => {
            let val: u64 = try!(read_int(buf));
            pos += 8;
            ValueRef::Integer(Integer::U64(val))
        }
        Marker::NegativeFixnum(val) => {
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I8 => {
            let val: i8 = try!(read_int(buf));
            pos += 1;
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I16 => {
            let val: i16 = try!(read_int(buf));
            pos += 2;
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I32 => {
            let val: i32 = try!(read_int(buf));
            pos += 4;
            ValueRef::Integer(Integer::I64(val as i64))
        }
        Marker::I64 => {
            let val: i64 = try!(read_int(buf));
            pos += 8;
            ValueRef::Integer(Integer::I64(val))
        }
        Marker::F32 => {
            unimplemented!();
        }
        Marker::F64 => {
            unimplemented!();
        }
        Marker::FixedString(len) => {
            pos += len as usize;
            try!(read_str_value(buf, len))
        }
        Marker::Str8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 1 + len as usize;
            try!(read_str_value(buf, len))
        }
        Marker::Str16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 2 + len as usize;
            try!(read_str_value(buf, len))
        }
        Marker::Str32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 4 + len as usize;
            try!(read_str_value(buf, len))
        }
        Marker::Bin8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 1 + len as usize;
            try!(read_bin_value(buf, len))
        }
        Marker::Bin16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 2 + len as usize;
            try!(read_bin_value(buf, len))
        }
        Marker::Bin32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 4 + len as usize;
            try!(read_bin_value(buf, len))
        }
        Marker::FixedArray(len) => {
            let len = len as usize;
            let (vec, bytes) = try!(read_array(&mut buf, len));
            pos += bytes;
            ValueRef::Array(vec)
        }
        Marker::Array16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            let len = len as usize;
            let (vec, bytes) = try!(read_array(&mut buf, len));
            pos += bytes;
            ValueRef::Array(vec)
        }
        Marker::Array32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            let len = len as usize;
            let (vec, bytes) = try!(read_array(&mut buf, len));
            pos += bytes;
            ValueRef::Array(vec)
        }
        Marker::FixedMap(len) => {
            let len = len as usize;
            let (map, bytes) = try!(read_map(&mut buf, len));
            pos += bytes;
            ValueRef::Map(map)
        }
        Marker::Map16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            let len = len as usize; // TODO: Possible overflow.
            let (map, bytes) = try!(read_map(&mut buf, len));
            pos += 2 + bytes;
            ValueRef::Map(map)
        }
        Marker::Map32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            let len = len as usize; // TODO: Possible overflow.
            let (map, bytes) = try!(read_map(&mut buf, len));
            pos += 4 + bytes;
            ValueRef::Map(map)
        }
        Marker::FixExt1 => {
            let len: u8 = 1;
            pos += 2;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::FixExt2 => {
            let len: u8 = 2;
            pos += 3;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::FixExt4 => {
            let len: u8 = 4;
            pos += 5;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::FixExt8 => {
            let len: u8 = 8;
            pos += 9;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::FixExt16 => {
            let len: u8 = 16;
            pos += 17;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::Ext8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 2 + len as usize;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::Ext16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 3 + len as usize;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::Ext32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            pos += 5 + len as usize;
            try!(read_ext_value(&mut buf, len))
        }
        Marker::Reserved => unimplemented!()
    };

    Ok((val, pos as usize))
}

// NOTE: Consumes nothing from the given `BufRead` both on success and fail.
// TODO: Possible non-mut reference will be better.
pub fn read_value_ref<R>(rd: &mut R) -> Result<ValueRef, Error>
    where R: BufRead
{
    let buf = try!(rd.fill_buf().map_err(|err| Error::InvalidBufferFill(err)));
    let res = try!(read_value_ref_impl(buf)).0;
    Ok(res)
}

// TODO: Concepts: less code; more tests; fast refactoring after each test; no more than 5 min for
// each red-yellow-green.
<|endoftext|>


<commit_before>use crate::modules::{compile_hello, fib_mock, null_mock};
use criterion::Criterion;
use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate};
use lucetc::OptLevel;
use rayon::prelude::*;
use std::sync::Arc;
use tempfile::TempDir;

/// Common definiton of OptLevel
const BENCHMARK_OPT_LEVEL: OptLevel = OptLevel::SpeedAndSize;

/// Parallel instantiation.
///
/// This measures how well the region handles concurrent instantiations from multiple
/// threads. Scaling is not necessarily the point here, due to the locks on the region freelist and
/// memory management syscalls, but we do want to make sure the concurrent case isn't slower than
/// single-threaded.
fn par_instantiate<R: RegionCreate + 'static>(c: &mut Criterion) {
    const INSTANCES_PER_RUN: usize = 2000;

    fn setup<R: RegionCreate + 'static>() -> (Arc<R>, Vec<Option<InstanceHandle>>) {
        let region = R::create(INSTANCES_PER_RUN, &Limits::default()).unwrap();
        let mut handles = vec![];
        handles.resize_with(INSTANCES_PER_RUN, || None);
        (region, handles)
    }

    fn body<R: Region>(
        num_threads: usize,
        module: Arc<dyn Module>,
        region: Arc<R>,
        handles: &mut [Option<InstanceHandle>],
    ) {
        rayon::ThreadPoolBuilder::new()
            .num_threads(num_threads)
            .build()
            .unwrap()
            .install(|| {
                handles
                    .par_iter_mut()
                    .for_each(|handle| *handle = Some(region.new_instance(module.clone()).unwrap()))
            })
    }

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, BENCHMARK_OPT_LEVEL);

    let module = DlModule::load(&so_file).unwrap();

    let bench = criterion::ParameterizedBenchmark::new(
        format!("par_instantiate ({})", R::TYPE_NAME),
        move |b, &num_threads| {
            b.iter_batched(
                setup,
                |(region, mut handles): (Arc<R>, _)| {
                    body(num_threads, module.clone(), region, handles.as_mut_slice())
                },
                criterion::BatchSize::SmallInput,
            )
        },
        (1..=num_cpus::get_physical()).collect::<Vec<usize>>(),
    )
    .sample_size(10);

    c.bench("par", bench);

    workdir.close().unwrap();
}

/// Run a function in parallel.
fn par_run<R: RegionCreate + 'static>(
    name: &str,
    instances_per_run: usize,
    module: Arc<dyn Module>,
    c: &mut Criterion,
) {
    let setup = move || {
        let region = R::create(instances_per_run, &Limits::default()).unwrap();

        (0..instances_per_run)
            .map(|_| region.new_instance(module.clone()).unwrap())
            .collect::<Vec<InstanceHandle>>()
    };

    fn body(num_threads: usize, handles: &mut [InstanceHandle]) {
        rayon::ThreadPoolBuilder::new()
            .num_threads(num_threads)
            .build()
            .unwrap()
            .install(|| {
                handles.par_iter_mut().for_each(|handle| {
                    handle.run("f", &[]).unwrap();
                })
            })
    }

    let bench = criterion::ParameterizedBenchmark::new(
        name,
        move |b, &num_threads| {
            b.iter_batched_ref(
                setup.clone(),
                |handles| body(num_threads, handles.as_mut_slice()),
                criterion::BatchSize::SmallInput,
            )
        },
        (1..=num_cpus::get_physical()).collect::<Vec<usize>>(),
    )
    .sample_size(10);

    c.bench("par", bench);
}

/// Run a function in parallel, controlling signal handlers and stacks manually.
fn par_run_manual_signals<R: RegionCreate + 'static>(
    name: &str,
    instances_per_run: usize,
    module: Arc<dyn Module>,
    c: &mut Criterion,
) {
    struct SignalState {
        #[allow(unused)]
        // this has to stick around so the sigstack remains valid memory
        sigstack: Vec<u8>,
        saved_sigstack: libc::stack_t,
    }

    impl SignalState {
        fn new() -> Self {
            lucet_runtime::install_lucet_signal_handler();

            let mut sigstack = vec![0; lucet_runtime::DEFAULT_SIGNAL_STACK_SIZE];
            let sigstack_raw = libc::stack_t {
                ss_sp: sigstack.as_mut_ptr() as *mut _,
                ss_flags: 0,
                ss_size: lucet_runtime::DEFAULT_SIGNAL_STACK_SIZE,
            };
            let mut saved_sigstack = std::mem::MaybeUninit::<libc::stack_t>::uninit();
            let saved_sigstack = unsafe {
                libc::sigaltstack(&sigstack_raw, saved_sigstack.as_mut_ptr());
                saved_sigstack.assume_init()
            };

            Self {
                sigstack,
                saved_sigstack,
            }
        }
    }

    impl Drop for SignalState {
        fn drop(&mut self) {
            lucet_runtime::remove_lucet_signal_handler();
            unsafe {
                libc::sigaltstack(&self.saved_sigstack, std::ptr::null_mut());
            }
        }
    }

    let setup = move || {
        let region = R::create(instances_per_run, &Limits::default()).unwrap();

        (
            (0..instances_per_run)
                .map(|_| {
                    let mut inst = region.new_instance(module.clone()).unwrap();
                    inst.ensure_signal_handler_installed(false);
                    inst.ensure_sigstack_installed(false);
                    inst
                })
                .collect::<Vec<InstanceHandle>>(),
            SignalState::new(),
        )
    };

    fn body(num_threads: usize, handles: &mut [InstanceHandle]) {
        rayon::ThreadPoolBuilder::new()
            .num_threads(num_threads)
            .build()
            .unwrap()
            .install(|| {
                handles.par_iter_mut().for_each(|handle| {
                    handle.run("f", &[]).unwrap();
                })
            })
    }

    let bench = criterion::ParameterizedBenchmark::new(
        name,
        move |b, &num_threads| {
            b.iter_batched_ref(
                setup.clone(),
                |(handles, _)| body(num_threads, handles.as_mut_slice()),
                criterion::BatchSize::SmallInput,
            )
        },
        (1..=num_cpus::get_physical()).collect::<Vec<usize>>(),
    )
    .sample_size(10);

    c.bench("par", bench);
}

/// Run a trivial function in parallel.
///
/// This measures how well the region handles concurrent executions from multiple threads. Since the
/// body of the function is empty, scaling is not necessarily the point here, rather we want to make
/// sure that the locks for signal handling don't unduly slow the program down with multiple
/// threads.
fn par_run_null<R: RegionCreate + 'static>(c: &mut Criterion) {
    par_run::<R>(
        &format!("par_run_null ({})", R::TYPE_NAME),
        1000,
        null_mock(),
        c,
    );
    par_run_manual_signals::<R>(
        &format!("par_run_null_manual_signals ({})", R::TYPE_NAME),
        1000,
        null_mock(),
        c,
    );
}

/// Run a computation-heavy function in parallel.
///
/// Since running multiple independent fibonaccis is embarassingly parallel, this should scale close
/// to linearly.
fn par_run_fib<R: RegionCreate + 'static>(c: &mut Criterion) {
    par_run::<R>(
        &format!("par_run_fib ({})", R::TYPE_NAME),
        1000,
        fib_mock(),
        c,
    );
    par_run_manual_signals::<R>(
        &format!("par_run_fib_manual_signals ({})", R::TYPE_NAME),
        1000,
        fib_mock(),
        c,
    );
}

pub fn par_benches<R: RegionCreate + 'static>(c: &mut Criterion) {
    par_instantiate::<R>(c);
    par_run_null::<R>(c);
    par_run_fib::<R>(c);
}
<commit_msg>fix the manual sigstack benchmark<commit_after>use crate::modules::{compile_hello, fib_mock, null_mock};
use criterion::Criterion;
use lucet_runtime::{DlModule, InstanceHandle, Limits, Module, Region, RegionCreate};
use lucetc::OptLevel;
use rayon::prelude::*;
use std::sync::{Arc, Mutex};
use tempfile::TempDir;

/// Common definiton of OptLevel
const BENCHMARK_OPT_LEVEL: OptLevel = OptLevel::SpeedAndSize;

/// Parallel instantiation.
///
/// This measures how well the region handles concurrent instantiations from multiple
/// threads. Scaling is not necessarily the point here, due to the locks on the region freelist and
/// memory management syscalls, but we do want to make sure the concurrent case isn't slower than
/// single-threaded.
fn par_instantiate<R: RegionCreate + 'static>(c: &mut Criterion) {
    const INSTANCES_PER_RUN: usize = 2000;

    fn setup<R: RegionCreate + 'static>() -> (Arc<R>, Vec<Option<InstanceHandle>>) {
        let region = R::create(INSTANCES_PER_RUN, &Limits::default()).unwrap();
        let mut handles = vec![];
        handles.resize_with(INSTANCES_PER_RUN, || None);
        (region, handles)
    }

    fn body<R: Region>(
        num_threads: usize,
        module: Arc<dyn Module>,
        region: Arc<R>,
        handles: &mut [Option<InstanceHandle>],
    ) {
        rayon::ThreadPoolBuilder::new()
            .num_threads(num_threads)
            .build()
            .unwrap()
            .install(|| {
                handles
                    .par_iter_mut()
                    .for_each(|handle| *handle = Some(region.new_instance(module.clone()).unwrap()))
            })
    }

    let workdir = TempDir::new().expect("create working directory");

    let so_file = workdir.path().join("out.so");
    compile_hello(&so_file, BENCHMARK_OPT_LEVEL);

    let module = DlModule::load(&so_file).unwrap();

    let bench = criterion::ParameterizedBenchmark::new(
        format!("par_instantiate ({})", R::TYPE_NAME),
        move |b, &num_threads| {
            b.iter_batched(
                setup,
                |(region, mut handles): (Arc<R>, _)| {
                    body(num_threads, module.clone(), region, handles.as_mut_slice())
                },
                criterion::BatchSize::SmallInput,
            )
        },
        (1..=num_cpus::get_physical()).collect::<Vec<usize>>(),
    )
    .sample_size(10);

    c.bench("par", bench);

    workdir.close().unwrap();
}

/// Run a function in parallel.
fn par_run<R: RegionCreate + 'static>(
    name: &str,
    instances_per_run: usize,
    module: Arc<dyn Module>,
    c: &mut Criterion,
) {
    let setup = move || {
        let region = R::create(instances_per_run, &Limits::default()).unwrap();

        (0..instances_per_run)
            .map(|_| region.new_instance(module.clone()).unwrap())
            .collect::<Vec<InstanceHandle>>()
    };

    fn body(num_threads: usize, handles: &mut [InstanceHandle]) {
        rayon::ThreadPoolBuilder::new()
            .num_threads(num_threads)
            .build()
            .unwrap()
            .install(|| {
                handles.par_iter_mut().for_each(|handle| {
                    handle.run("f", &[]).unwrap();
                })
            })
    }

    let bench = criterion::ParameterizedBenchmark::new(
        name,
        move |b, &num_threads| {
            b.iter_batched_ref(
                setup.clone(),
                |handles| body(num_threads, handles.as_mut_slice()),
                criterion::BatchSize::SmallInput,
            )
        },
        (1..=num_cpus::get_physical()).collect::<Vec<usize>>(),
    )
    .sample_size(10);

    c.bench("par", bench);
}

/// Run a function in parallel, controlling signal handlers and stacks manually.
fn par_run_manual_signals<R: RegionCreate + 'static>(
    name: &str,
    instances_per_run: usize,
    module: Arc<dyn Module>,
    c: &mut Criterion,
) {
    /// A guard to set up the manual signal handler, and automatically remove it when the benchmark
    /// is over.
    struct SignalGuard;

    impl SignalGuard {
        fn new() -> Self {
            lucet_runtime::install_lucet_signal_handler();
            Self
        }
    }

    impl Drop for SignalGuard {
        fn drop(&mut self) {
            lucet_runtime::remove_lucet_signal_handler();
        }
    }

    // make a vec full of ready-to-run instances, the Rayon thread pool, and intialize the `SignalGuard`
    let setup = move |num_threads| {
        move || {
            let region = R::create(instances_per_run, &Limits::default()).unwrap();
            let instances = (0..instances_per_run)
                .map(|_| {
                    let mut inst = region.new_instance(module.clone()).unwrap();
                    inst.ensure_signal_handler_installed(false);
                    inst.ensure_sigstack_installed(false);
                    inst
                })
                .collect::<Vec<InstanceHandle>>();
            let thread_pool = rayon::ThreadPoolBuilder::new()
                .num_threads(num_threads)
                // install an appropriately-sized sigaltstack for each thread that Rayon will run
                // instances on
                .start_handler(|_| {
                    thread_local! {
                        static SIGSTACK: Mutex<Vec<u8>> =
                            Mutex::new(vec![0; lucet_runtime::DEFAULT_SIGNAL_STACK_SIZE]);
                    }
                    SIGSTACK.with(|sigstack| {
                        let mut sigstack = sigstack.lock().unwrap();
                        let sigstack_raw = libc::stack_t {
                            ss_sp: sigstack.as_mut_ptr() as *mut _,
                            ss_flags: 0,
                            ss_size: lucet_runtime::DEFAULT_SIGNAL_STACK_SIZE,
                        };
                        unsafe {
                            libc::sigaltstack(&sigstack_raw, std::ptr::null_mut());
                        }
                    });
                })
                .build()
                .unwrap();
            let signal_guard = SignalGuard::new();

            (instances, thread_pool, signal_guard)
        }
    };

    let bench = criterion::ParameterizedBenchmark::new(
        name,
        move |b, &num_threads| {
            b.iter_batched_ref(
                setup.clone()(num_threads),
                |(handles, thread_pool, _signal_guard)| {
                    thread_pool.install(|| {
                        handles.par_iter_mut().for_each(|handle| {
                            handle.run("f", &[]).unwrap();
                        })
                    })
                },
                criterion::BatchSize::SmallInput,
            )
        },
        (1..=num_cpus::get_physical()).collect::<Vec<usize>>(),
    )
    .sample_size(10);

    c.bench("par", bench);
}

/// Run a trivial function in parallel.
///
/// This measures how well the region handles concurrent executions from multiple threads. Since the
/// body of the function is empty, scaling is not necessarily the point here, rather we want to make
/// sure that the locks for signal handling don't unduly slow the program down with multiple
/// threads.
fn par_run_null<R: RegionCreate + 'static>(c: &mut Criterion) {
    par_run::<R>(
        &format!("par_run_null ({})", R::TYPE_NAME),
        1000,
        null_mock(),
        c,
    );
    par_run_manual_signals::<R>(
        &format!("par_run_null_manual_signals ({})", R::TYPE_NAME),
        1000,
        null_mock(),
        c,
    );
}

/// Run a computation-heavy function in parallel.
///
/// Since running multiple independent fibonaccis is embarassingly parallel, this should scale close
/// to linearly.
fn par_run_fib<R: RegionCreate + 'static>(c: &mut Criterion) {
    par_run::<R>(
        &format!("par_run_fib ({})", R::TYPE_NAME),
        1000,
        fib_mock(),
        c,
    );
    par_run_manual_signals::<R>(
        &format!("par_run_fib_manual_signals ({})", R::TYPE_NAME),
        1000,
        fib_mock(),
        c,
    );
}

pub fn par_benches<R: RegionCreate + 'static>(c: &mut Criterion) {
    par_instantiate::<R>(c);
    par_run_null::<R>(c);
    par_run_fib::<R>(c);
}
<|endoftext|>


<commit_before>
use std::thread;
use ws;
use ws::{CloseCode, Handler, Message, Sender, listen};

#[derive(Debug, PartialEq)]
enum Action {
    Next,
    Step(u64),
    AddBreakPtn(u64),
    DelBreakPtn(u64),
    Err,
}

pub struct Debugger {
    pub step: u64,
}

struct Websocket(Sender);

impl Debugger {
    pub fn new() -> Debugger {
        let debugger = Debugger { step: 0 };
        debugger.listen();
        debugger
    }

    fn listen(&self) {
        thread::spawn(move || { listen("127.0.0.1:3012", |out| Websocket(out)).unwrap(); });
    }
}

impl Handler for Websocket {
    fn on_message(&mut self, msg: Message) -> ws::Result<()> {
        println!("{:?}", handle(msg.as_text().unwrap()));
        Ok(())
    }

    fn on_close(&mut self, code: CloseCode, reason: &str) {
        println!("WebSocket closing for ({:?}) {}", code, reason);
    }
}

//TODO: Better error handling
fn handle(s: &str) -> Result<Action, ()> {
    let mut split = s.split(",");

    let cmd: &str = match split.next() {
        Some(e) => e,
        None => return Err(()),
    };

    let opt: u64 = match (split.next(), cmd) {
        (None, "Next") => 0,
        (Some(e), _) => {
            match e.parse::<u64>() {
                Ok(u) => match u {
                    0 => return Err(()),
                    _ => u
                },
                Err(_) => return Err(()),
            }
        }
        (None, _) => return Err(()),
    };

    match cmd {
        "Next" => Ok(Action::Next),
        "Step" => Ok(Action::Step(opt)),
        "AddBreakPtn" => Ok(Action::AddBreakPtn(opt)),
        "DelBreakPtn" => Ok(Action::DelBreakPtn(opt)),
        _ => Err(()),
    }
}

#[test]
fn handle_cmd() {
    assert_eq!(handle("Next"), Ok(Action::Next));
    assert_eq!(handle("Step,45"), Ok(Action::Step(45)));
    assert_eq!(handle("AddBreakPtn,678"), Ok(Action::AddBreakPtn(678)));
    assert_eq!(handle("DelBreakPtn,654"), Ok(Action::DelBreakPtn(654)));

    assert_eq!(handle("Foo"), Err(()));
    assert_eq!(handle("Step,-45"), Err(()));
    assert_eq!(handle("AddBreakPtn"), Err(()));
    assert_eq!(handle("DelBreakPtn,0"), Err(()));

}
<commit_msg>better parsing<commit_after>
use std::thread;
use ws;
use ws::{CloseCode, Handler, Message, Sender, listen};

#[derive(Debug, PartialEq)]
enum Action {
    Next,
    Step(u64),
    AddBreakPtn(u64),
    DelBreakPtn(u64),
    Err,
}

pub struct Debugger {
    pub step: u64,
}

struct Websocket(Sender);

impl Debugger {
    pub fn new() -> Debugger {
        let debugger = Debugger { step: 0 };
        debugger.listen();
        debugger
    }

    fn listen(&self) {
        thread::spawn(move || { listen("127.0.0.1:3012", |out| Websocket(out)).unwrap(); });
    }
}

impl Handler for Websocket {
    fn on_message(&mut self, msg: Message) -> ws::Result<()> {
        println!("{:?}", handle(msg.as_text().unwrap()));
        Ok(())
    }

    fn on_close(&mut self, code: CloseCode, reason: &str) {
        println!("WebSocket closing for ({:?}) {}", code, reason);
    }
}

//TODO: Better error handling
fn handle(s: &str) -> Result<Action, ()> {
    let mut split = s.split(",");

    let cmd: &str = match split.next() {
        Some(e) => e.trim(),
        None => return Err(()),
    };

    let opt: u64 = match (split.next(), cmd) {
        (None, "Next") => 0,
        (Some(e), _) => {
            match e.trim().parse::<u64>() {
                Ok(u) => match u {
                    0 => return Err(()),
                    _ => u
                },
                Err(_) => return Err(()),
            }
        }
        (None, _) => return Err(()),
    };

    match cmd {
        "Next" => Ok(Action::Next),
        "Step" => Ok(Action::Step(opt)),
        "AddBreakPtn" => Ok(Action::AddBreakPtn(opt)),
        "DelBreakPtn" => Ok(Action::DelBreakPtn(opt)),
        _ => Err(()),
    }
}

#[test]
fn handle_cmd() {
    assert_eq!(handle("Next"), Ok(Action::Next));
    assert_eq!(handle("Step,45"), Ok(Action::Step(45)));
    assert_eq!(handle("AddBreakPtn,678"), Ok(Action::AddBreakPtn(678)));
    assert_eq!(handle("DelBreakPtn,654"), Ok(Action::DelBreakPtn(654)));
    assert_eq!(handle("DelBreakPtn  , 67  "), Ok(Action::DelBreakPtn(67)));
    assert_eq!(handle("DelBreakPtn, coucou"), Err(()));

    assert_eq!(handle("Foo"), Err(()));
    assert_eq!(handle("Step,-45"), Err(()));
    assert_eq!(handle("AddBreakPtn"), Err(()));
    assert_eq!(handle("DelBreakPtn,0"), Err(()));

}
<|endoftext|>


<commit_before>//! Compiler plugin for Rust-Phf
//!
//! See the documentation for the `phf` crate for more details.
#[crate_id="github.com/sfackler/rust-phf/phf_mac"];
#[crate_type="lib"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[feature(managed_boxes, macro_registrar)];

extern mod syntax;

use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        SyntaxExpanderTT,
                        SyntaxExpanderTTExpanderWithoutContext};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{COMMA, EOF, FAT_ARROW};

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~SyntaxExpanderTT {
                expander: SyntaxExpanderTTExpanderWithoutContext(expand_mphf_map),
                span: None
             },
             None));
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut pairs = ~[];

    while parser.token != EOF {
        let key = parser.parse_expr();

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(s, _) => s,
                    _ => cx.span_fatal(key.span, "expected string literal"),
                }
            }
            _ => cx.span_fatal(key.span, "expected string literal"),
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_fatal(parser.span, "expected `=>`");
        }

        let value = parser.parse_expr();

        pairs.push((key_str, key, value));

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_fatal(parser.span, "expected `,`");
        }
    }

    pairs.sort_by(|&(ref a, _, _), &(ref b, _, _)| a.cmp(b));
    check_for_duplicates(cx, sp, pairs);

    let entries = pairs.move_iter()
        .map(|(_, key, value)| quote_expr!(&*cx, ($key, $value)))
        .collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap { entries: &'static $entries }))
}

fn check_for_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[(@str, @Expr, @Expr)]) {
    let mut in_dup = false;
    for window in entries.windows(2) {
        let (a, a_expr, _) = window[0];
        let (b, b_expr, _) = window[1];
        if a == b {
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a));
                cx.span_err(a_expr.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_err(b_expr.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }
    cx.parse_sess().span_diagnostic.handler().abort_if_errors();
}
<commit_msg>Stop using a tuple for map entries<commit_after>//! Compiler plugin for Rust-Phf
//!
//! See the documentation for the `phf` crate for more details.
#[crate_id="github.com/sfackler/rust-phf/phf_mac"];
#[crate_type="lib"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[feature(managed_boxes, macro_registrar)];

extern mod syntax;

use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        SyntaxExpanderTT,
                        SyntaxExpanderTTExpanderWithoutContext};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{COMMA, EOF, FAT_ARROW};

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~SyntaxExpanderTT {
                expander: SyntaxExpanderTTExpanderWithoutContext(expand_mphf_map),
                span: None
             },
             None));
}

struct Entry {
    key_str: @str,
    key: @Expr,
    value: @Expr
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut entries = ~[];

    while parser.token != EOF {
        let key = parser.parse_expr();

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(s, _) => s,
                    _ => cx.span_fatal(key.span, "expected string literal"),
                }
            }
            _ => cx.span_fatal(key.span, "expected string literal"),
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_fatal(parser.span, "expected `=>`");
        }

        let value = parser.parse_expr();

        entries.push(Entry {
            key_str: key_str,
            key: key,
            value: value
        });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_fatal(parser.span, "expected `,`");
        }
    }

    entries.sort_by(|a, b| a.key_str.cmp(&b.key_str));
    check_for_duplicates(cx, sp, entries);

    let entries = entries.move_iter()
        .map(|Entry { key, value, .. }| quote_expr!(&*cx, ($key, $value)))
        .collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap { entries: &'static $entries }))
}

fn check_for_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) {
    let mut in_dup = false;
    for window in entries.windows(2) {
        let ref a = window[0];
        let ref b = window[1];
        if a.key_str == b.key_str {
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a.key_str));
                cx.span_err(a.key.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_err(b.key.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }
    cx.parse_sess().span_diagnostic.handler().abort_if_errors();
}
<|endoftext|>


<commit_before>#![feature(env)]
#![feature(fs)]
#![feature(io)]
#![feature(old_path)]

use std::io::prelude::*; // imports all the io related stuff altogether
use std::fs::File; // imports the File struct which holds information about a file
use std::env;

fn main() {

    let args: Vec<String> = env::args().collect();
    for idx in 0..args.len() {
        println!("argument #{}: {}", idx, args[idx]);
    }

    let path: Path = Path::new(&args[1]); // creates a path to our file
    let display = path.display(); // for safely printing paths

    let mut input_file: File = match File::open(&path) {

        // Err and Ok are parts of the Result struct, Err contains the cause of an error, Ok has the result
        Err(reason) => panic!("Couldn't open {}, the reason: {}", display, reason.description()),

        Ok(file) => file,

    };

    let mut file_row = String::new();
    match input_file.read_to_string(&mut file_row) {

        Err(why) => panic!("Couldn't read from the file, reason {}", why.description()),

        Ok(_) => print!("{}", file_row),

    }

}
<commit_msg>Updated rustc. Had to update the code to get rid of the new warnings...<commit_after>use std::io::prelude::*; // imports all the io related stuff altogether
use std::fs::File; // imports the File struct which holds information about a file
use std::env;
use std::path::Path;

fn main() {

    let args: Vec<String> = env::args().collect();
    for idx in 0..args.len() {
        println!("argument #{}: {}", idx, args[idx]);
    }

    let path  = Path::new(&args[1]); // creates a path to our file
    let display = path.display(); // for safely printing paths

    let mut input_file: File = match File::open(&path) {

        // Err and Ok are parts of the Result struct, Err contains the cause of an error, Ok has the result
        Err(reason) => panic!("Couldn't open {}, the reason: {}", display, reason),

        Ok(file) => file,

    };

    let mut file_row = String::new();
    match input_file.read_to_string(&mut file_row) {

        Err(why) => panic!("Couldn't read from the file, reason {}", why),

        Ok(_) => print!("{}", file_row),

    }

    let mut my_vector: Vec<i32> = Vec::new();
    my_vector.push(3);

}
<|endoftext|>


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

#[test]
fn test_is_lowercase() {
    assert!('a'.is_lowercase());
    assert!('ö'.is_lowercase());
    assert!('ß'.is_lowercase());
    assert!(!'Ü'.is_lowercase());
    assert!(!'P'.is_lowercase());
}

#[test]
fn test_is_uppercase() {
    assert!(!'h'.is_uppercase());
    assert!(!'ä'.is_uppercase());
    assert!(!'ß'.is_uppercase());
    assert!('Ö'.is_uppercase());
    assert!('T'.is_uppercase());
}

#[test]
fn test_is_whitespace() {
    assert!(' '.is_whitespace());
    assert!('\u{2007}'.is_whitespace());
    assert!('\t'.is_whitespace());
    assert!('\n'.is_whitespace());
    assert!(!'a'.is_whitespace());
    assert!(!'_'.is_whitespace());
    assert!(!'\u{0}'.is_whitespace());
}

#[test]
fn test_to_digit() {
    assert_eq!('0'.to_digit(10), Some(0));
    assert_eq!('1'.to_digit(2), Some(1));
    assert_eq!('2'.to_digit(3), Some(2));
    assert_eq!('9'.to_digit(10), Some(9));
    assert_eq!('a'.to_digit(16), Some(10));
    assert_eq!('A'.to_digit(16), Some(10));
    assert_eq!('b'.to_digit(16), Some(11));
    assert_eq!('B'.to_digit(16), Some(11));
    assert_eq!('z'.to_digit(36), Some(35));
    assert_eq!('Z'.to_digit(36), Some(35));
    assert_eq!(' '.to_digit(10), None);
    assert_eq!('$'.to_digit(36), None);
}

#[test]
fn test_to_lowercase() {
    fn lower(c: char) -> char {
        let mut it = c.to_lowercase();
        let c = it.next().unwrap();
        // As of Unicode version 7.0.0, `SpecialCasing.txt` has no lower-case mapping
        // to multiple code points.
        assert!(it.next().is_none());
        c
    }
    assert_eq!(lower('A'), 'a');
    assert_eq!(lower('Ö'), 'ö');
    assert_eq!(lower('ß'), 'ß');
    assert_eq!(lower('Ü'), 'ü');
    assert_eq!(lower('💩'), '💩');
    assert_eq!(lower('Σ'), 'σ');
    assert_eq!(lower('Τ'), 'τ');
    assert_eq!(lower('Ι'), 'ι');
    assert_eq!(lower('Γ'), 'γ');
    assert_eq!(lower('Μ'), 'μ');
    assert_eq!(lower('Α'), 'α');
    assert_eq!(lower('Σ'), 'σ');
    assert_eq!(lower('ǅ'), 'ǆ');
    assert_eq!(lower('ﬁ'), 'ﬁ');
}

#[test]
fn test_to_uppercase() {
    fn upper(c: char) -> Vec<char> {
        c.to_uppercase().collect()
    }
    assert_eq!(upper('a'), ['A']);
    assert_eq!(upper('ö'), ['Ö']);
    assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s
    assert_eq!(upper('ü'), ['Ü']);
    assert_eq!(upper('💩'), ['💩']);

    assert_eq!(upper('σ'), ['Σ']);
    assert_eq!(upper('τ'), ['Τ']);
    assert_eq!(upper('ι'), ['Ι']);
    assert_eq!(upper('γ'), ['Γ']);
    assert_eq!(upper('μ'), ['Μ']);
    assert_eq!(upper('α'), ['Α']);
    assert_eq!(upper('ς'), ['Σ']);
    assert_eq!(upper('ǅ'), ['Ǆ']);
    assert_eq!(upper('ﬁ'), ['F', 'I']);
    assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']);
}

#[test]
fn test_is_control() {
    assert!('\u{0}'.is_control());
    assert!('\u{3}'.is_control());
    assert!('\u{6}'.is_control());
    assert!('\u{9}'.is_control());
    assert!('\u{7f}'.is_control());
    assert!('\u{92}'.is_control());
    assert!(!'\u{20}'.is_control());
    assert!(!'\u{55}'.is_control());
    assert!(!'\u{68}'.is_control());
}

#[test]
fn test_is_digit() {
   assert!('2'.is_numeric());
   assert!('7'.is_numeric());
   assert!(!'c'.is_numeric());
   assert!(!'i'.is_numeric());
   assert!(!'z'.is_numeric());
   assert!(!'Q'.is_numeric());
}

#[test]
fn test_escape_default() {
    fn string(c: char) -> String {
        c.escape_default().collect()
    }
    let s = string('\n');
    assert_eq!(s, "\\n");
    let s = string('\r');
    assert_eq!(s, "\\r");
    let s = string('\'');
    assert_eq!(s, "\\'");
    let s = string('"');
    assert_eq!(s, "\\\"");
    let s = string(' ');
    assert_eq!(s, " ");
    let s = string('a');
    assert_eq!(s, "a");
    let s = string('~');
    assert_eq!(s, "~");
    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\x1f');
    assert_eq!(s, "\\u{1f}");
    let s = string('\x7f');
    assert_eq!(s, "\\u{7f}");
    let s = string('\u{ff}');
    assert_eq!(s, "\\u{ff}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_escape_unicode() {
    fn string(c: char) -> String { c.escape_unicode().collect() }

    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\n');
    assert_eq!(s, "\\u{a}");
    let s = string(' ');
    assert_eq!(s, "\\u{20}");
    let s = string('a');
    assert_eq!(s, "\\u{61}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_encode_utf8() {
    fn check(input: char, expect: &[u8]) {
        let mut buf = [0; 4];
        let n = input.encode_utf8(&mut buf).unwrap_or(0);
        assert_eq!(&buf[..n], expect);
    }

    check('x', &[0x78]);
    check('\u{e9}', &[0xc3, 0xa9]);
    check('\u{a66e}', &[0xea, 0x99, 0xae]);
    check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]);
}

#[test]
fn test_encode_utf16() {
    fn check(input: char, expect: &[u16]) {
        let mut buf = [0; 2];
        let n = input.encode_utf16(&mut buf).unwrap_or(0);
        assert_eq!(&buf[..n], expect);
    }

    check('x', &[0x0078]);
    check('\u{e9}', &[0x00e9]);
    check('\u{a66e}', &[0xa66e]);
    check('\u{1f4a9}', &[0xd83d, 0xdca9]);
}

#[test]
fn test_len_utf16() {
    assert!('x'.len_utf16() == 1);
    assert!('\u{e9}'.len_utf16() == 1);
    assert!('\u{a66e}'.len_utf16() == 1);
    assert!('\u{1f4a9}'.len_utf16() == 2);
}
<commit_msg>Add a test for char::to_lowercase mapping to more than one `char`.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[test]
fn test_is_lowercase() {
    assert!('a'.is_lowercase());
    assert!('ö'.is_lowercase());
    assert!('ß'.is_lowercase());
    assert!(!'Ü'.is_lowercase());
    assert!(!'P'.is_lowercase());
}

#[test]
fn test_is_uppercase() {
    assert!(!'h'.is_uppercase());
    assert!(!'ä'.is_uppercase());
    assert!(!'ß'.is_uppercase());
    assert!('Ö'.is_uppercase());
    assert!('T'.is_uppercase());
}

#[test]
fn test_is_whitespace() {
    assert!(' '.is_whitespace());
    assert!('\u{2007}'.is_whitespace());
    assert!('\t'.is_whitespace());
    assert!('\n'.is_whitespace());
    assert!(!'a'.is_whitespace());
    assert!(!'_'.is_whitespace());
    assert!(!'\u{0}'.is_whitespace());
}

#[test]
fn test_to_digit() {
    assert_eq!('0'.to_digit(10), Some(0));
    assert_eq!('1'.to_digit(2), Some(1));
    assert_eq!('2'.to_digit(3), Some(2));
    assert_eq!('9'.to_digit(10), Some(9));
    assert_eq!('a'.to_digit(16), Some(10));
    assert_eq!('A'.to_digit(16), Some(10));
    assert_eq!('b'.to_digit(16), Some(11));
    assert_eq!('B'.to_digit(16), Some(11));
    assert_eq!('z'.to_digit(36), Some(35));
    assert_eq!('Z'.to_digit(36), Some(35));
    assert_eq!(' '.to_digit(10), None);
    assert_eq!('$'.to_digit(36), None);
}

#[test]
fn test_to_lowercase() {
    fn lower(c: char) -> Vec<char> {
        c.to_lowercase().collect()
    }
    assert_eq!(lower('A'), ['a']);
    assert_eq!(lower('Ö'), ['ö']);
    assert_eq!(lower('ß'), ['ß']);
    assert_eq!(lower('Ü'), ['ü']);
    assert_eq!(lower('💩'), ['💩']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('Τ'), ['τ']);
    assert_eq!(lower('Ι'), ['ι']);
    assert_eq!(lower('Γ'), ['γ']);
    assert_eq!(lower('Μ'), ['μ']);
    assert_eq!(lower('Α'), ['α']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('ǅ'), ['ǆ']);
    assert_eq!(lower('ﬁ'), ['ﬁ']);
    assert_eq!(lower('İ'), ['i', '\u{307}']);
}

#[test]
fn test_to_uppercase() {
    fn upper(c: char) -> Vec<char> {
        c.to_uppercase().collect()
    }
    assert_eq!(upper('a'), ['A']);
    assert_eq!(upper('ö'), ['Ö']);
    assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s
    assert_eq!(upper('ü'), ['Ü']);
    assert_eq!(upper('💩'), ['💩']);

    assert_eq!(upper('σ'), ['Σ']);
    assert_eq!(upper('τ'), ['Τ']);
    assert_eq!(upper('ι'), ['Ι']);
    assert_eq!(upper('γ'), ['Γ']);
    assert_eq!(upper('μ'), ['Μ']);
    assert_eq!(upper('α'), ['Α']);
    assert_eq!(upper('ς'), ['Σ']);
    assert_eq!(upper('ǅ'), ['Ǆ']);
    assert_eq!(upper('ﬁ'), ['F', 'I']);
    assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']);
}

#[test]
fn test_is_control() {
    assert!('\u{0}'.is_control());
    assert!('\u{3}'.is_control());
    assert!('\u{6}'.is_control());
    assert!('\u{9}'.is_control());
    assert!('\u{7f}'.is_control());
    assert!('\u{92}'.is_control());
    assert!(!'\u{20}'.is_control());
    assert!(!'\u{55}'.is_control());
    assert!(!'\u{68}'.is_control());
}

#[test]
fn test_is_digit() {
   assert!('2'.is_numeric());
   assert!('7'.is_numeric());
   assert!(!'c'.is_numeric());
   assert!(!'i'.is_numeric());
   assert!(!'z'.is_numeric());
   assert!(!'Q'.is_numeric());
}

#[test]
fn test_escape_default() {
    fn string(c: char) -> String {
        c.escape_default().collect()
    }
    let s = string('\n');
    assert_eq!(s, "\\n");
    let s = string('\r');
    assert_eq!(s, "\\r");
    let s = string('\'');
    assert_eq!(s, "\\'");
    let s = string('"');
    assert_eq!(s, "\\\"");
    let s = string(' ');
    assert_eq!(s, " ");
    let s = string('a');
    assert_eq!(s, "a");
    let s = string('~');
    assert_eq!(s, "~");
    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\x1f');
    assert_eq!(s, "\\u{1f}");
    let s = string('\x7f');
    assert_eq!(s, "\\u{7f}");
    let s = string('\u{ff}');
    assert_eq!(s, "\\u{ff}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_escape_unicode() {
    fn string(c: char) -> String { c.escape_unicode().collect() }

    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\n');
    assert_eq!(s, "\\u{a}");
    let s = string(' ');
    assert_eq!(s, "\\u{20}");
    let s = string('a');
    assert_eq!(s, "\\u{61}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_encode_utf8() {
    fn check(input: char, expect: &[u8]) {
        let mut buf = [0; 4];
        let n = input.encode_utf8(&mut buf).unwrap_or(0);
        assert_eq!(&buf[..n], expect);
    }

    check('x', &[0x78]);
    check('\u{e9}', &[0xc3, 0xa9]);
    check('\u{a66e}', &[0xea, 0x99, 0xae]);
    check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]);
}

#[test]
fn test_encode_utf16() {
    fn check(input: char, expect: &[u16]) {
        let mut buf = [0; 2];
        let n = input.encode_utf16(&mut buf).unwrap_or(0);
        assert_eq!(&buf[..n], expect);
    }

    check('x', &[0x0078]);
    check('\u{e9}', &[0x00e9]);
    check('\u{a66e}', &[0xa66e]);
    check('\u{1f4a9}', &[0xd83d, 0xdca9]);
}

#[test]
fn test_len_utf16() {
    assert!('x'.len_utf16() == 1);
    assert!('\u{e9}'.len_utf16() == 1);
    assert!('\u{a66e}'.len_utf16() == 1);
    assert!('\u{1f4a9}'.len_utf16() == 2);
}
<|endoftext|>


<commit_before>use datum::*;
use primitive::*;
use numeric::LNumeric;
use std::fun_treemap;
use std::fun_treemap::Treemap;
use core::num::Zero::zero;
use core::num::One::one;

struct Runtime {
    stdin: @io::Reader,
    stdout: @io::Writer,
    stderr: @io::Writer,
    global: Treemap<@str, @LDatum>,
    syntax: Treemap<@str, PrimSyntax>,
}

#[deriving(Eq)]
enum RuntimeError {
    UnboundVariable(@str),
    NotCallable,
    NotList,
    ArgNumError,
    TypeError,
    DivideByZeroError,
    NilEval,
    BadSyntax(PrimSyntax, ~str),
}

impl ToStr for RuntimeError {
    fn to_str(&self) -> ~str {
        err_to_str(self)
    }
}

priv fn err_to_str(&err: &RuntimeError) -> ~str {
    match err {
        UnboundVariable(name) => ~"unbound variable: " + name,
        NotCallable => ~"not callable",
        NotList => ~"not list",
        ArgNumError => ~"bad number of arguments",
        TypeError => ~"type error",
        DivideByZeroError => ~"divide by zero",
        NilEval => ~"() cannot be evaluated",
        BadSyntax(syn, reason) => ~"bad syntax for " + syn.to_str() + ": " + reason,
    }
}

fn load_prelude() -> Treemap<@str, @LDatum> {
    let mut map = fun_treemap::init();
    for vec::each(prelude()) |&pair| {
        let (key, func) = pair;
        map = fun_treemap::insert(map, key, @LPrim(func));
    }
    map
}

fn load_prelude_macro() -> Treemap<@str, PrimSyntax> {
    let mut map = fun_treemap::init();
    for vec::each(syntax_prelude()) |&pair| {
        let (key, syntax) = pair;
        map = fun_treemap::insert(map, key, syntax);
    }
    map
}

priv fn call_prim1(args: ~[@LDatum],
                op: &fn(@LDatum) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 1 {
        op(args[0])
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_prim2(args: ~[@LDatum],
                    op: &fn(&LNumeric, &LNumeric) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 2 {
        match *args[0] {
            LNum(lhs) => match *args[1] {
                LNum(rhs) => op(&lhs, &rhs),
                _ => Err(TypeError),
            },
            _ => Err(TypeError),
        }
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_foldl(args: ~[@LDatum],
                    a0: LNumeric,
                    op: &fn(&LNumeric, &LNumeric) -> Result<LNumeric, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    let mut res = a0;
    let mut err = false;
    do args.each |&arg| {
        match *arg {
            LNum(a) => {
                match op(&res, &a) {
                    Ok(n) => {
                        res = n;
                        err = false;
                    },
                    _ => {
                        err = true;
                    }
                }
            },
            _ => {
                err = true;
            }
        }
        !err
    }
    if err {
        Err(TypeError)
    } else {
        Ok(@LNum(res))
    }
}

priv impl Runtime {
    fn get_syntax(&self, val: @LDatum) -> Option<PrimSyntax> {
        match *val {
            LIdent(name) => fun_treemap::find(self.syntax, name),
            _ => None,
        }
    }

    fn run_syntax(&self,
                syn: PrimSyntax,
                args: ~[@LDatum],
                stack: Treemap<@str, @LDatum>) -> Result<@LDatum, RuntimeError>
    {
        match syn {
            SynIf => if args.len() == 3 {
                    do result::chain(self.eval_local(args[0], stack)) |cond| {
                        match *cond {
                            LBool(true) => self.eval_local(args[1], stack),
                            LBool(false) => self.eval_local(args[2], stack),
                            _ => Err(TypeError),
                        }
                    }
                } else {
                    Err(BadSyntax(SynIf, ~"bad number of arguments"))
                },
            SynLambda => if args.len() < 2 {
                    Err(BadSyntax(SynLambda, ~"no procedure given"))
                } else {
                    match args[0].to_list() {
                        None => Err(BadSyntax(SynLambda, ~"non-list arguments")),
                        Some(largs) => {
                            let names = do result::map_vec(largs) |&arg| {
                                match *arg {
                                    LIdent(name) => Ok(name),
                                    _ => Err(BadSyntax(SynLambda, ~"non-symbol arguments")),
                                }
                            };
                            do result::map(&names) |&anames| {
                                let seq = vec::from_slice(vec::slice(args, 1, args.len()));
                                @LProc(anames, seq)
                            }
                        },
                    }
                },
            SynQuote => if args.len() == 1 {
                    Ok(args[0])
                } else {
                    Err(BadSyntax(SynQuote, ~"bad number of arguments"))
                },
        }
    }

    fn call_proc(&self,
                anames: &~[@str],
                code: &~[@LDatum],
                args: ~[@LDatum],
                stack: Treemap<@str, @LDatum>) -> Result<@LDatum, RuntimeError>
    {
        if anames.len() != args.len() {
            Err(ArgNumError)
        } else {
            let mut new_stack = stack;
            for uint::range(0, anames.len()) |i| {
                new_stack = fun_treemap::insert(new_stack, anames[i], args[i]);
            }

            let mut res:Result<@LDatum, RuntimeError> = Err(NilEval);
            do code.each() |&val| {
                res = self.eval_local(val, new_stack);
                res.is_ok()
            }

            res
        }
    }

    fn call_prim(&self,
                f: PFunc,
                args: ~[@LDatum],
                stack: Treemap<@str, @LDatum>) -> Result<@LDatum, RuntimeError>
    {
        match f {
            PEval => do call_prim1(args) |arg| {
                self.eval_local(arg, stack)
            },
            PAdd => do call_num_foldl(args, zero()) |&lhs, &rhs| { Ok(lhs + rhs) },
            PSub => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs - rhs) },
            PMul => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs * rhs) },
            PDiv => do call_num_foldl(args, one()) |&lhs, &rhs| {
                if rhs.is_zero() {
                    Err(DivideByZeroError)
                } else {
                    Ok(lhs / rhs)
                }
            },
            PCar => do call_prim1(args) |arg| {
                match *arg {
                    LCons(h, _) => Ok(h),
                    _ => Err(TypeError),
                }
            },
            PCdr => do call_prim1(args) |arg| {
                match *arg {
                    LCons(_, t) => Ok(t),
                    _ => Err(TypeError),
                }
            },
        }
    }

    fn eager_eval(&self,
                aexprs: ~[@LDatum],
                stack: Treemap<@str, @LDatum>,
                f: &fn(~[@LDatum]) -> Result<@LDatum, RuntimeError>)
                    -> Result<@LDatum, RuntimeError>
    {
        match result::map_vec(aexprs,
                            |&expr| self.eval_local(expr, stack))
        {
            Ok(args) => f(args),
            Err(e) => Err(e),
        }
    }

    fn eval_local(&self,
                val: @LDatum,
                stack: Treemap<@str, @LDatum>) -> Result<@LDatum, RuntimeError>
    {
        match *val {
            LIdent(name) =>
                match fun_treemap::find(stack, name) {
                    Some(datum) => Ok(datum),
                    None => Err(UnboundVariable(name)),
                },
            LCons(fexpr, aexpr) =>
                match aexpr.to_list() {
                    None => Err(NotList),
                    Some(aexprs) => {
                        match self.get_syntax(fexpr) {
                            Some(syntax) =>
                                self.run_syntax(syntax, aexprs, stack),
                            None =>
                                match self.eval_local(fexpr, stack) {
                                    Ok(@LPrim(f)) =>
                                        do self.eager_eval(aexprs, stack) |args| {
                                            self.call_prim(f, args, stack)
                                        },
                                    Ok(@LProc(ref anames, ref code)) =>
                                        do self.eager_eval(aexprs, stack) |args| {
                                            self.call_proc(anames, code, args, stack)
                                        },
                                    Ok(_) => Err(NotCallable),
                                    Err(e) => Err(e),
                                },
                        }
                    },
                },
            LQuote(val) => Ok(val),
            LNil => Err(NilEval),
            _ => Ok(val),
        }
    }
}

pub impl Runtime {
    fn new_std() -> Runtime {
        Runtime {
            stdin: io::stdin(),
            stdout: io::stdout(),
            stderr: io::stderr(),
            global: load_prelude(),
            syntax: load_prelude_macro(),
        }
    }

    fn eval(&self, val: @LDatum) -> Result<@LDatum, RuntimeError> {
        self.eval_local(val, self.global)
    }
}
<commit_msg>make runtime mutable<commit_after>use datum::*;
use primitive::*;
use numeric::LNumeric;
use std::fun_treemap;
use std::fun_treemap::Treemap;
use core::num::Zero::zero;
use core::num::One::one;

enum Stack<T> {
    Top(T, @Stack<T>),
    Bot,
}

struct Runtime {
    stdin: @io::Reader,
    stdout: @io::Writer,
    stderr: @io::Writer,
    stack: @Stack<Treemap<@str, @LDatum>>,
    syntax: Treemap<@str, PrimSyntax>,
}

#[deriving(Eq)]
enum RuntimeError {
    UnboundVariable(@str),
    NotCallable,
    NotList,
    ArgNumError,
    TypeError,
    DivideByZeroError,
    NilEval,
    BadSyntax(PrimSyntax, ~str),
}

impl ToStr for RuntimeError {
    fn to_str(&self) -> ~str {
        err_to_str(self)
    }
}

priv fn err_to_str(&err: &RuntimeError) -> ~str {
    match err {
        UnboundVariable(name) => ~"unbound variable: " + name,
        NotCallable => ~"not callable",
        NotList => ~"not list",
        ArgNumError => ~"bad number of arguments",
        TypeError => ~"type error",
        DivideByZeroError => ~"divide by zero",
        NilEval => ~"() cannot be evaluated",
        BadSyntax(syn, reason) => ~"bad syntax for " + syn.to_str() + ": " + reason,
    }
}

fn load_prelude() -> Treemap<@str, @LDatum> {
    let mut map = fun_treemap::init();
    for vec::each(prelude()) |&pair| {
        let (key, func) = pair;
        map = fun_treemap::insert(map, key, @LPrim(func));
    }
    map
}

fn load_prelude_macro() -> Treemap<@str, PrimSyntax> {
    let mut map = fun_treemap::init();
    for vec::each(syntax_prelude()) |&pair| {
        let (key, syntax) = pair;
        map = fun_treemap::insert(map, key, syntax);
    }
    map
}

priv fn call_prim1(args: ~[@LDatum],
                op: &fn(@LDatum) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 1 {
        op(args[0])
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_prim2(args: ~[@LDatum],
                    op: &fn(&LNumeric, &LNumeric) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 2 {
        match *args[0] {
            LNum(lhs) => match *args[1] {
                LNum(rhs) => op(&lhs, &rhs),
                _ => Err(TypeError),
            },
            _ => Err(TypeError),
        }
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_foldl(args: ~[@LDatum],
                    a0: LNumeric,
                    op: &fn(&LNumeric, &LNumeric) -> Result<LNumeric, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    let mut res = a0;
    let mut err = false;
    do args.each |&arg| {
        match *arg {
            LNum(a) => {
                match op(&res, &a) {
                    Ok(n) => {
                        res = n;
                        err = false;
                    },
                    _ => {
                        err = true;
                    }
                }
            },
            _ => {
                err = true;
            }
        }
        !err
    }
    if err {
        Err(TypeError)
    } else {
        Ok(@LNum(res))
    }
}

priv impl Runtime {
    fn get_syntax(&self, val: @LDatum) -> Option<PrimSyntax> {
        match *val {
            LIdent(name) => fun_treemap::find(self.syntax, name),
            _ => None,
        }
    }

    fn run_syntax(&mut self,
                syn: PrimSyntax,
                args: ~[@LDatum]) -> Result<@LDatum, RuntimeError>
    {
        match syn {
            SynIf => if args.len() == 3 {
                    do result::chain(self.eval(args[0])) |cond| {
                        match *cond {
                            LBool(true) => self.eval(args[1]),
                            LBool(false) => self.eval(args[2]),
                            _ => Err(TypeError),
                        }
                    }
                } else {
                    Err(BadSyntax(SynIf, ~"bad number of arguments"))
                },
            SynLambda => if args.len() < 2 {
                    Err(BadSyntax(SynLambda, ~"no procedure given"))
                } else {
                    match args[0].to_list() {
                        None => Err(BadSyntax(SynLambda, ~"non-list arguments")),
                        Some(largs) => {
                            let names = do result::map_vec(largs) |&arg| {
                                match *arg {
                                    LIdent(name) => Ok(name),
                                    _ => Err(BadSyntax(SynLambda, ~"non-symbol arguments")),
                                }
                            };
                            do result::map(&names) |&anames| {
                                let seq = vec::from_slice(vec::slice(args, 1, args.len()));
                                @LProc(anames, seq)
                            }
                        },
                    }
                },
            SynQuote => if args.len() == 1 {
                    Ok(args[0])
                } else {
                    Err(BadSyntax(SynQuote, ~"bad number of arguments"))
                },
        }
    }

    fn call_proc(&mut self,
                anames: &~[@str],
                code: &~[@LDatum],
                args: ~[@LDatum]) -> Result<@LDatum, RuntimeError>
    {
        if anames.len() != args.len() {
            Err(ArgNumError)
        } else {
            // store current stack
            let old_stack = self.stack;

            let mut frame =
            match *old_stack {
                // this is a critical failure
                Bot => fail!(~"stack underflow"),
                Top(st, _) => st,
            };

            for uint::range(0, anames.len()) |i| {
                frame = fun_treemap::insert(frame, anames[i], args[i]);
            }

            // add new frame to the stack
            self.stack = @Top(frame, old_stack);

            let mut res:Result<@LDatum, RuntimeError> = Err(NilEval);
            do code.each() |&val| {
                res = self.eval(val);
                res.is_ok()
            }

            // restore stack
            self.stack = old_stack;

            res
        }
    }

    fn call_prim(&mut self,
                f: PFunc,
                args: ~[@LDatum]) -> Result<@LDatum, RuntimeError>
    {
        match f {
            PEval => do call_prim1(args) |arg| {
                self.eval(arg)
            },
            PAdd => do call_num_foldl(args, zero()) |&lhs, &rhs| { Ok(lhs + rhs) },
            PSub => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs - rhs) },
            PMul => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs * rhs) },
            PDiv => do call_num_foldl(args, one()) |&lhs, &rhs| {
                if rhs.is_zero() {
                    Err(DivideByZeroError)
                } else {
                    Ok(lhs / rhs)
                }
            },
            PCar => do call_prim1(args) |arg| {
                match *arg {
                    LCons(h, _) => Ok(h),
                    _ => Err(TypeError),
                }
            },
            PCdr => do call_prim1(args) |arg| {
                match *arg {
                    LCons(_, t) => Ok(t),
                    _ => Err(TypeError),
                }
            },
        }
    }
}

pub impl Runtime {
    fn new_std() -> Runtime {
        Runtime {
            stdin: io::stdin(),
            stdout: io::stdout(),
            stderr: io::stderr(),
            stack: @Top(load_prelude(), @Bot),
            syntax: load_prelude_macro(),
        }
    }

    fn eval(&mut self, val: @LDatum) -> Result<@LDatum, RuntimeError>
    {
        match *val {
            LIdent(name) =>
                match *self.stack {
                    Bot => fail!(~"stack underflow"),
                    Top(frame, _) => match fun_treemap::find(frame, name) {
                        Some(datum) => Ok(datum),
                        None => Err(UnboundVariable(name)),
                    },
                },
            LCons(fexpr, aexpr) =>
                match aexpr.to_list() {
                    None => Err(NotList),
                    Some(aexprs) => {
                        match self.get_syntax(fexpr) {
                            Some(syntax) =>
                                self.run_syntax(syntax, aexprs),
                            None =>
                                match self.eval(fexpr) {
                                    Ok(@LPrim(f)) =>
                                        match result::map_vec(aexprs, |&expr| self.eval(expr))
                                        {
                                            Ok(args) => self.call_prim(f, args),
                                            Err(e) => Err(e),
                                        },
                                    Ok(@LProc(ref anames, ref code)) =>
                                        match result::map_vec(aexprs, |&expr| self.eval(expr))
                                        {
                                            Ok(args) => self.call_proc(anames, code, args),
                                            Err(e) => Err(e),
                                        },
                                    Ok(_) => Err(NotCallable),
                                    Err(e) => Err(e),
                                },
                        }
                    },
                },
            LQuote(val) => Ok(val),
            LNil => Err(NilEval),
            _ => Ok(val),
        }
    }
}
<|endoftext|>


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

#[allow(non_camel_case_types)];

use cast;
use libc;
use ops::Drop;
use uint;
use ptr;

#[cfg(windows)]
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T,
                                   LPVOID, DWORD, LPDWORD, HANDLE};

#[cfg(windows)] type rust_thread = HANDLE;
#[cfg(unix)] type rust_thread = libc::pthread_t;

pub struct Thread {
    priv native: rust_thread,
    priv joined: bool
}

static DEFAULT_STACK_SIZE: libc::size_t = 1024*1024;

#[cfg(windows)] type rust_thread_return = DWORD;
#[cfg(unix)] type rust_thread_return = *libc::c_void;

impl Thread {

    pub fn start(main: proc()) -> Thread {
        // This is the starting point of rust os threads. The first thing we do
        // is make sure that we don't trigger __morestack (also why this has a
        // no_split_stack annotation), and then we extract the main function
        // and invoke it.
        #[no_split_stack]
        extern "C" fn thread_start(trampoline: *libc::c_void) -> rust_thread_return {
            use rt::context;
            unsafe {
                context::record_stack_bounds(0, uint::max_value);
                let f: ~proc() = cast::transmute(trampoline);
                (*f)();
            }
            unsafe { cast::transmute(0) }
        }

        let native = native_thread_create(thread_start, ~main);
        Thread {
            native: native,
            joined: false,
        }
    }

    pub fn join(mut self) {
        assert!(!self.joined);
        native_thread_join(self.native);
        self.joined = true;
    }
}

#[cfg(windows)]
fn native_thread_create(thread_start: extern "C" fn(*libc::c_void) -> rust_thread_return,
                        tramp: ~proc()) -> rust_thread {
    unsafe {
        let ptr: *mut libc::c_void = cast::transmute(tramp);
        CreateThread(ptr::mut_null(), DEFAULT_STACK_SIZE, thread_start, ptr, 0, ptr::mut_null())
    }
}

#[cfg(windows)]
fn native_thread_join(native: rust_thread) {
    use libc::consts::os::extra::INFINITE;
    unsafe { WaitForSingleObject(native, INFINITE); }
}

#[cfg(unix)]
fn native_thread_create(thread_start: extern "C" fn(*libc::c_void) -> rust_thread_return,
                        tramp: ~proc()) -> rust_thread {
    use unstable::intrinsics;
    let mut native: libc::pthread_t = unsafe { intrinsics::uninit() };

    unsafe {
        use libc::consts::os::posix01::PTHREAD_CREATE_JOINABLE;

        let mut attr: libc::pthread_attr_t = intrinsics::uninit();
        assert!(pthread_attr_init(&mut attr) == 0);
        assert!(pthread_attr_setstacksize(&mut attr, DEFAULT_STACK_SIZE) == 0);
        assert!(pthread_attr_setdetachstate(&mut attr, PTHREAD_CREATE_JOINABLE) == 0);

        let ptr: *libc::c_void = cast::transmute(tramp);
        assert!(pthread_create(&mut native, &attr, thread_start, ptr) == 0);
    }
    native
}

#[cfg(unix)]
fn native_thread_join(native: rust_thread) {
    unsafe { assert!(pthread_join(native, ptr::null()) == 0) }
}

impl Drop for Thread {
    fn drop(&mut self) {
        assert!(self.joined);
    }
}

#[cfg(windows)]
extern "system" {
    fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T,
                    lpStartAddress: extern "C" fn(*libc::c_void) -> rust_thread_return,
                    lpParameter: LPVOID, dwCreationFlags: DWORD, lpThreadId: LPDWORD) -> HANDLE;
    fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
}

#[cfg(unix)]
extern {
    fn pthread_create(native: *mut libc::pthread_t, attr: *libc::pthread_attr_t,
                      f: extern "C" fn(*libc::c_void) -> rust_thread_return,
                      value: *libc::c_void) -> libc::c_int;
    fn pthread_join(native: libc::pthread_t, value: **libc::c_void) -> libc::c_int;
    fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
                                 stack_size: libc::size_t) -> libc::c_int;
    fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
                                   state: libc::c_int) -> libc::c_int;
}
<commit_msg>std: Fix transmute error on win64<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[allow(non_camel_case_types)];

use cast;
use libc;
use ops::Drop;
use uint;
use ptr;

#[cfg(windows)]
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T,
                                   LPVOID, DWORD, LPDWORD, HANDLE};

#[cfg(windows)] type rust_thread = HANDLE;
#[cfg(unix)] type rust_thread = libc::pthread_t;

pub struct Thread {
    priv native: rust_thread,
    priv joined: bool
}

static DEFAULT_STACK_SIZE: libc::size_t = 1024*1024;

#[cfg(windows)] type rust_thread_return = DWORD;
#[cfg(unix)] type rust_thread_return = *libc::c_void;

impl Thread {

    pub fn start(main: proc()) -> Thread {
        // This is the starting point of rust os threads. The first thing we do
        // is make sure that we don't trigger __morestack (also why this has a
        // no_split_stack annotation), and then we extract the main function
        // and invoke it.
        #[no_split_stack]
        extern "C" fn thread_start(trampoline: *libc::c_void) -> rust_thread_return {
            use rt::context;
            unsafe {
                context::record_stack_bounds(0, uint::max_value);
                let f: ~proc() = cast::transmute(trampoline);
                (*f)();
            }
            unsafe { cast::transmute(0 as rust_thread_return) }
        }

        let native = native_thread_create(thread_start, ~main);
        Thread {
            native: native,
            joined: false,
        }
    }

    pub fn join(mut self) {
        assert!(!self.joined);
        native_thread_join(self.native);
        self.joined = true;
    }
}

#[cfg(windows)]
fn native_thread_create(thread_start: extern "C" fn(*libc::c_void) -> rust_thread_return,
                        tramp: ~proc()) -> rust_thread {
    unsafe {
        let ptr: *mut libc::c_void = cast::transmute(tramp);
        CreateThread(ptr::mut_null(), DEFAULT_STACK_SIZE, thread_start, ptr, 0, ptr::mut_null())
    }
}

#[cfg(windows)]
fn native_thread_join(native: rust_thread) {
    use libc::consts::os::extra::INFINITE;
    unsafe { WaitForSingleObject(native, INFINITE); }
}

#[cfg(unix)]
fn native_thread_create(thread_start: extern "C" fn(*libc::c_void) -> rust_thread_return,
                        tramp: ~proc()) -> rust_thread {
    use unstable::intrinsics;
    let mut native: libc::pthread_t = unsafe { intrinsics::uninit() };

    unsafe {
        use libc::consts::os::posix01::PTHREAD_CREATE_JOINABLE;

        let mut attr: libc::pthread_attr_t = intrinsics::uninit();
        assert!(pthread_attr_init(&mut attr) == 0);
        assert!(pthread_attr_setstacksize(&mut attr, DEFAULT_STACK_SIZE) == 0);
        assert!(pthread_attr_setdetachstate(&mut attr, PTHREAD_CREATE_JOINABLE) == 0);

        let ptr: *libc::c_void = cast::transmute(tramp);
        assert!(pthread_create(&mut native, &attr, thread_start, ptr) == 0);
    }
    native
}

#[cfg(unix)]
fn native_thread_join(native: rust_thread) {
    unsafe { assert!(pthread_join(native, ptr::null()) == 0) }
}

impl Drop for Thread {
    fn drop(&mut self) {
        assert!(self.joined);
    }
}

#[cfg(windows)]
extern "system" {
    fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T,
                    lpStartAddress: extern "C" fn(*libc::c_void) -> rust_thread_return,
                    lpParameter: LPVOID, dwCreationFlags: DWORD, lpThreadId: LPDWORD) -> HANDLE;
    fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
}

#[cfg(unix)]
extern {
    fn pthread_create(native: *mut libc::pthread_t, attr: *libc::pthread_attr_t,
                      f: extern "C" fn(*libc::c_void) -> rust_thread_return,
                      value: *libc::c_void) -> libc::c_int;
    fn pthread_join(native: libc::pthread_t, value: **libc::c_void) -> libc::c_int;
    fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
                                 stack_size: libc::size_t) -> libc::c_int;
    fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
                                   state: libc::c_int) -> libc::c_int;
}
<|endoftext|>