<commit_before>#![crate_name = "rust-hl-lua"]
#![crate_type = "lib"]
#![comment = "Lua bindings for Rust"]
#![license = "MIT"]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]

extern crate libc;
extern crate collections;

use std::io::IoError;
use std::kinds::marker::ContravariantLifetime;

pub use lua_tables::LuaTable;
pub use functions_read::LuaFunction;

pub mod any;
pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod ffi;
mod functions_write;
mod rust_tables;
mod tuples;
mod values;

/// Main object of the library.
/// The lifetime parameter corresponds to the lifetime of the Lua object itself.
#[unstable]
pub struct Lua<'lua> {
    lua: *mut ffi::lua_State,
    marker: ContravariantLifetime<'lua>,
    must_be_closed: bool,
}

/// Trait for objects that have access to a Lua context.
/// The lifetime parameter is the lifetime of the Lua context.
pub trait HasLua {
    fn use_lua(&mut self) -> *mut ffi::lua_State;
}

impl<'lua> HasLua for Lua<'lua> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.lua
    }
}

/// Object which allows access to a Lua variable.
#[doc(hidden)]
pub struct LoadedVariable<'var, L: 'var> {
    lua: &'var mut L,
    size: uint,       // number of elements over "lua"
}

impl<'var, 'lua, L: HasLua> HasLua for LoadedVariable<'var, L> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.lua.use_lua()
    }
}

/// Should be implemented by whatever type is pushable on the Lua stack.
#[unstable]
pub trait Push<L> {
    /// Pushes the value on the top of the stack.
    /// Must return the number of elements pushed.
    ///
    /// You can implement this for any type you want by redirecting to call to
    /// another implementation (for example `5.push_to_lua`) or by calling `userdata::push_userdata`
    fn push_to_lua(self, lua: &mut L) -> uint;
}

/// Should be implemented by types that can be read by consomming a LoadedVariable.
#[unstable]
pub trait ConsumeRead<'a, L> {
    /// Returns the LoadedVariable in case of failure.
    fn read_from_variable(var: LoadedVariable<'a, L>) -> Result<Self, LoadedVariable<'a, L>>;
}

/// Should be implemented by whatever type can be read by copy from the Lua stack.
#[unstable]
pub trait CopyRead<L> {
    /// Reads an object from the Lua stack.
    ///
    /// Similar to Push, you can implement this trait for your own types either by
    /// redirecting the calls to another implementation or by calling userdata::read_copy_userdata
    ///
    /// # Arguments
    ///  * `lua` - The Lua object to read from
    ///  * `index` - The index on the stack to read from
    fn read_from_lua(lua: &mut L, index: i32) -> Option<Self>;
}

/// Types that can be indices in Lua tables.
#[unstable]
pub trait Index<L>: Push<L> + CopyRead<L> {
}

/// Error that can happen when executing Lua code.
#[deriving(Show)]
#[unstable]
pub enum LuaError {
    /// There was a syntax error when parsing the Lua code.
    SyntaxError(String),

    /// There was an error during execution of the Lua code
    /// (for example not enough parameters for a function call).
    ExecutionError(String),

    /// There was an IoError while reading the source code to execute.
    ReadError(IoError),

    /// The call to `execute` has requested the wrong type of data.
    WrongType
}

// this alloc function is required to create a lua state.
extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t, nsize: libc::size_t) -> *mut libc::c_void {
    unsafe {
        if nsize == 0 {
            libc::free(ptr as *mut libc::c_void);
            std::ptr::null_mut()
        } else {
            libc::realloc(ptr, nsize)
        }
    }
}

// called whenever lua encounters an unexpected error.
extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
    let err = unsafe { ffi::lua_tostring(lua, -1) };
    panic!("PANIC: unprotected error in call to Lua API ({})\n", err);
}

impl<'lua> Lua<'lua> {
    /// Builds a new Lua context.
    ///
    /// # Panic
    /// The function panics if lua_newstate fails (which indicates lack of memory).
    #[stable]
    pub fn new() -> Lua<'lua> {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::null_mut()) };
        if lua.is_null() {
            panic!("lua_newstate failed");
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: lua,
            marker: ContravariantLifetime,
            must_be_closed: true,
        }
    }

    /// Takes an existing lua_State and build a Lua object from it.
    ///
    /// # Arguments
    ///  * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
    #[unstable]
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua<'lua> {
        Lua {
            lua: std::mem::transmute(lua),
            marker: ContravariantLifetime,
            must_be_closed: close_at_the_end,
        }
    }

    /// Opens all standard Lua libraries.
    /// This is done by calling `luaL_openlibs`.
    #[unstable]
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua) }
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute<'a, T: CopyRead<LoadedVariable<'a, Lua<'lua>>>>(&'a mut self, code: &str) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute_from_reader<'a, T: CopyRead<LoadedVariable<'a, Lua<'lua>>>, R: std::io::Reader + 'static>(&'a mut self, code: R) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /// Loads the value of a global variable.
    #[unstable]
    pub fn load<'a, I: Str, V: ConsumeRead<'a, Lua<'lua>>>(&'a mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        ConsumeRead::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok()
    }

    /// Loads the value of a global variable as a table.
    #[unstable]
    pub fn load_table<'a, I: Str>(&'a mut self, index: I) -> Option<LuaTable<Lua<'lua>>> {
        self.load(index)
    }

    /// Reads the value of a global variable by copying it.
    #[unstable]
    pub fn get<I: Str, V: CopyRead<Lua<'lua>>>(&mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        CopyRead::read_from_lua(self, -1)
    }

    /// Modifies the value of a global variable.
    #[unstable]
    pub fn set<I: Str, V: Push<Lua<'lua>>>(&mut self, index: I, value: V) {
        value.push_to_lua(self);
        unsafe { ffi::lua_setglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
    }

    #[unstable]
    pub fn load_new_table<'var>(&'var mut self) -> LuaTable<'var, Lua<'lua>> {
        unsafe { ffi::lua_newtable(self.lua) };
        ConsumeRead::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok().unwrap()
    }
}

#[unsafe_destructor]
impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua) }
        }
    }
}

// TODO: crashes the compiler
#[unsafe_destructor]
impl<'a, L: HasLua> Drop for LoadedVariable<'a, L> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.use_lua(), self.size as libc::c_int) }
    }
}
<commit_msg>Implement Error trait for LuaError<commit_after>#![crate_name = "rust-hl-lua"]
#![crate_type = "lib"]
#![comment = "Lua bindings for Rust"]
#![license = "MIT"]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]

extern crate libc;
extern crate collections;

use std::error::Error;
use std::io::IoError;
use std::kinds::marker::ContravariantLifetime;

pub use lua_tables::LuaTable;
pub use functions_read::LuaFunction;

pub mod any;
pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod ffi;
mod functions_write;
mod rust_tables;
mod tuples;
mod values;

/// Main object of the library.
/// The lifetime parameter corresponds to the lifetime of the Lua object itself.
#[unstable]
pub struct Lua<'lua> {
    lua: *mut ffi::lua_State,
    marker: ContravariantLifetime<'lua>,
    must_be_closed: bool,
}

/// Trait for objects that have access to a Lua context.
/// The lifetime parameter is the lifetime of the Lua context.
pub trait HasLua {
    fn use_lua(&mut self) -> *mut ffi::lua_State;
}

impl<'lua> HasLua for Lua<'lua> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.lua
    }
}

/// Object which allows access to a Lua variable.
#[doc(hidden)]
pub struct LoadedVariable<'var, L: 'var> {
    lua: &'var mut L,
    size: uint,       // number of elements over "lua"
}

impl<'var, 'lua, L: HasLua> HasLua for LoadedVariable<'var, L> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.lua.use_lua()
    }
}

/// Should be implemented by whatever type is pushable on the Lua stack.
#[unstable]
pub trait Push<L> {
    /// Pushes the value on the top of the stack.
    /// Must return the number of elements pushed.
    ///
    /// You can implement this for any type you want by redirecting to call to
    /// another implementation (for example `5.push_to_lua`) or by calling `userdata::push_userdata`
    fn push_to_lua(self, lua: &mut L) -> uint;
}

/// Should be implemented by types that can be read by consomming a LoadedVariable.
#[unstable]
pub trait ConsumeRead<'a, L> {
    /// Returns the LoadedVariable in case of failure.
    fn read_from_variable(var: LoadedVariable<'a, L>) -> Result<Self, LoadedVariable<'a, L>>;
}

/// Should be implemented by whatever type can be read by copy from the Lua stack.
#[unstable]
pub trait CopyRead<L> {
    /// Reads an object from the Lua stack.
    ///
    /// Similar to Push, you can implement this trait for your own types either by
    /// redirecting the calls to another implementation or by calling userdata::read_copy_userdata
    ///
    /// # Arguments
    ///  * `lua` - The Lua object to read from
    ///  * `index` - The index on the stack to read from
    fn read_from_lua(lua: &mut L, index: i32) -> Option<Self>;
}

/// Types that can be indices in Lua tables.
#[unstable]
pub trait Index<L>: Push<L> + CopyRead<L> {
}

/// Error that can happen when executing Lua code.
#[deriving(Show)]
#[unstable]
pub enum LuaError {
    /// There was a syntax error when parsing the Lua code.
    SyntaxError(String),

    /// There was an error during execution of the Lua code
    /// (for example not enough parameters for a function call).
    ExecutionError(String),

    /// There was an IoError while reading the source code to execute.
    ReadError(IoError),

    /// The call to `execute` has requested the wrong type of data.
    WrongType
}

impl Error for LuaError {
    fn description(&self) -> &str {
        match self {
            &LuaError::SyntaxError(_) => "Syntax error when parsing Lua code",
            &LuaError::ExecutionError(_) => "Error while executing Lua code",
            &LuaError::ReadError(_) => "Error while reading the Lua source code",
            &LuaError::WrongType => "Wrong type of data requested when executing Lua code",
        }
    }

    fn detail(&self) -> Option<String> {
        match self {
            &LuaError::SyntaxError(ref s) => Some(s.clone()),
            &LuaError::ExecutionError(ref s) => Some(s.clone()),
            _ => None,
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &LuaError::ReadError(ref e) => Some(e as &Error),
            _ => None,
        }
    }
}

// this alloc function is required to create a lua state.
extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t, nsize: libc::size_t) -> *mut libc::c_void {
    unsafe {
        if nsize == 0 {
            libc::free(ptr as *mut libc::c_void);
            std::ptr::null_mut()
        } else {
            libc::realloc(ptr, nsize)
        }
    }
}

// called whenever lua encounters an unexpected error.
extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
    let err = unsafe { ffi::lua_tostring(lua, -1) };
    panic!("PANIC: unprotected error in call to Lua API ({})\n", err);
}

impl<'lua> Lua<'lua> {
    /// Builds a new Lua context.
    ///
    /// # Panic
    /// The function panics if lua_newstate fails (which indicates lack of memory).
    #[stable]
    pub fn new() -> Lua<'lua> {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::null_mut()) };
        if lua.is_null() {
            panic!("lua_newstate failed");
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: lua,
            marker: ContravariantLifetime,
            must_be_closed: true,
        }
    }

    /// Takes an existing lua_State and build a Lua object from it.
    ///
    /// # Arguments
    ///  * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
    #[unstable]
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua<'lua> {
        Lua {
            lua: std::mem::transmute(lua),
            marker: ContravariantLifetime,
            must_be_closed: close_at_the_end,
        }
    }

    /// Opens all standard Lua libraries.
    /// This is done by calling `luaL_openlibs`.
    #[unstable]
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua) }
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute<'a, T: CopyRead<LoadedVariable<'a, Lua<'lua>>>>(&'a mut self, code: &str) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute_from_reader<'a, T: CopyRead<LoadedVariable<'a, Lua<'lua>>>, R: std::io::Reader + 'static>(&'a mut self, code: R) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /// Loads the value of a global variable.
    #[unstable]
    pub fn load<'a, I: Str, V: ConsumeRead<'a, Lua<'lua>>>(&'a mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        ConsumeRead::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok()
    }

    /// Loads the value of a global variable as a table.
    #[unstable]
    pub fn load_table<'a, I: Str>(&'a mut self, index: I) -> Option<LuaTable<Lua<'lua>>> {
        self.load(index)
    }

    /// Reads the value of a global variable by copying it.
    #[unstable]
    pub fn get<I: Str, V: CopyRead<Lua<'lua>>>(&mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        CopyRead::read_from_lua(self, -1)
    }

    /// Modifies the value of a global variable.
    #[unstable]
    pub fn set<I: Str, V: Push<Lua<'lua>>>(&mut self, index: I, value: V) {
        value.push_to_lua(self);
        unsafe { ffi::lua_setglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
    }

    #[unstable]
    pub fn load_new_table<'var>(&'var mut self) -> LuaTable<'var, Lua<'lua>> {
        unsafe { ffi::lua_newtable(self.lua) };
        ConsumeRead::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok().unwrap()
    }
}

#[unsafe_destructor]
impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua) }
        }
    }
}

// TODO: crashes the compiler
#[unsafe_destructor]
impl<'a, L: HasLua> Drop for LoadedVariable<'a, L> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.use_lua(), self.size as libc::c_int) }
    }
}
<|endoftext|>


<commit_before>use std::io::Read;

use common;

#[derive(Default)]
pub struct Day05 {}

impl Day05 {
    pub fn new() -> Day05 {
        Default::default()
    }

    fn reduce(mut data: Vec<u8>) -> usize {
        let mut dptr = 0;
        for iptr in 0..data.len() {
            if dptr > 0 && (data[iptr] ^ data[dptr - 1]) == 32 {
                dptr -= 1;
            } else {
                data[dptr] = data[iptr];
                dptr += 1;
            }
        }

        dptr
    }
}

impl common::Solution for Day05 {
    fn part1(&mut self, input: &mut Read) -> String {
        let mut data = Vec::new();
        input.read_to_end(&mut data).expect("Can't read input!");
        common::trim_back(&mut data);

        format!("{}", Day05::reduce(data))
    }

    fn part2(&mut self, input: &mut Read) -> String {
        let mut data = Vec::new();
        input.read_to_end(&mut data).expect("Can't read input!");
        common::trim_back(&mut data);

        let min_len = (b'a'..=b'z').map(|option| data.iter().filter(|&x| !x.eq_ignore_ascii_case(&option)).map(|&x| x).collect())
            .map(|x| Day05::reduce(x))
            .min().unwrap();

        format!("{}", min_len)
    }
}

#[cfg(test)]
mod tests {
    use common::Solution;
    use day05::Day05;

    const SAMPLE_INPUT: &[u8] = include_bytes!("samples/05");

    #[test]
    fn sample_part1() {
        let mut instance = Day05::new();
        assert_eq!("10", instance.part1(&mut SAMPLE_INPUT));
    }

    #[test]
    fn sample_part2() {
        let mut instance = Day05::new();
        assert_eq!("4", instance.part2(&mut SAMPLE_INPUT));
    }
}
<commit_msg>Clarify bitmagic.<commit_after>use std::io::Read;

use common;

#[derive(Default)]
pub struct Day05 {}

impl Day05 {
    pub fn new() -> Day05 {
        Default::default()
    }

    fn reduce(mut data: Vec<u8>) -> usize {
        let mut dptr = 0;
        for iptr in 0..data.len() {
            // This originally had a nice comparison
            // data[iptr] != data[dptr - 1] && data[iptr].eq_ignore_ascii_case(data[dptr - 1])
            // However this is way faster, and does about the same
            if dptr > 0 && (data[iptr] ^ data[dptr - 1]) == 32 {
                dptr -= 1;
            } else {
                data[dptr] = data[iptr];
                dptr += 1;
            }
        }

        dptr
    }
}

impl common::Solution for Day05 {
    fn part1(&mut self, input: &mut Read) -> String {
        let mut data = Vec::new();
        input.read_to_end(&mut data).expect("Can't read input!");
        common::trim_back(&mut data);

        format!("{}", Day05::reduce(data))
    }

    fn part2(&mut self, input: &mut Read) -> String {
        let mut data = Vec::new();
        input.read_to_end(&mut data).expect("Can't read input!");
        common::trim_back(&mut data);

        let min_len = (b'a'..=b'z').map(|option| data.iter().filter(|&x| !x.eq_ignore_ascii_case(&option)).map(|&x| x).collect())
            .map(|x| Day05::reduce(x))
            .min().unwrap();

        format!("{}", min_len)
    }
}

#[cfg(test)]
mod tests {
    use common::Solution;
    use day05::Day05;

    const SAMPLE_INPUT: &[u8] = include_bytes!("samples/05");

    #[test]
    fn sample_part1() {
        let mut instance = Day05::new();
        assert_eq!("10", instance.part1(&mut SAMPLE_INPUT));
    }

    #[test]
    fn sample_part2() {
        let mut instance = Day05::new();
        assert_eq!("4", instance.part2(&mut SAMPLE_INPUT));
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::ops::RangeInclusive;

use crate::common::Lines;
use crate::Solution;

fn split_nums<'a>(s: &'a str) -> impl Iterator<Item = u32> + 'a {
    s.split(|c: char| !c.is_ascii_digit()).filter_map(|s| {
        if s.is_empty() {
            None
        } else {
            Some(s.parse().unwrap())
        }
    })
}

fn read_input(input: &mut dyn Read) -> (HashMap<String, Vec<RangeInclusive<u32>>>, Vec<Vec<u32>>) {
    let mut lines = Lines::new(input).filter(|s| !s.is_empty());

    let mut rules = HashMap::new();
    let mut tickets = Vec::new();

    while let Some(line) = lines.next() {
        if line.as_str() == "your ticket:" {
            break;
        }

        let colon = line.find(':').unwrap();

        let nums: Vec<_> = split_nums(&line[colon..]).collect();

        let ranges: Vec<_> = nums.chunks_exact(2).map(|s| s[0]..=s[1]).collect();

        rules.insert(line[..colon].to_owned(), ranges);
    }

    while let Some(line) = lines.next() {
        if line.as_str() == "nearby tickets:" {
            continue;
        }

        tickets.push(split_nums(&line).collect());
    }

    (rules, tickets)
}

#[derive(Default)]
pub struct Day16;

impl Solution for Day16 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        let (rules, tickets) = read_input(input);

        let mut rate = 0;

        for ticket in &tickets[1..] {
            for value in ticket {
                if rules.values().flatten().all(|r| !r.contains(value)) {
                    rate += value;
                }
            }
        }

        rate.to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        let (rules, tickets) = read_input(input);
        let mut tickets = tickets;

        // O(n) operation but it's fine
        let my_ticket = tickets.remove(0);

        // Filter out invalid tickets
        tickets.retain(|t| {
            t.iter()
                .all(|v| rules.values().flatten().any(|r| r.contains(v)))
        });

        let all_fields: HashSet<_> = rules.keys().cloned().collect();

        let mut pos_can_be = vec![all_fields; my_ticket.len()];

        let mut fixed_fields = HashMap::new();

        for ticket in &tickets {
            for (field, ranges) in &rules {
                for (pos, value) in ticket.iter().enumerate() {
                    if pos_can_be[pos].len() <= 1 {
                        continue;
                    }

                    if !ranges.iter().any(|r| r.contains(value)) {
                        pos_can_be[pos].remove(field);
                    }
                }
            }
        }

        let mut can_fit: HashMap<&str, u64> = rules.keys().map(|k| (k.as_str(), 0)).collect();

        while fixed_fields.len() != rules.len() {
            // Fix fields that are the only option for a certain spot
            for pos in 0..pos_can_be.len() {
                if pos_can_be[pos].len() == 1 {
                    let field = pos_can_be[pos]
                        .drain()
                        .next()
                        .expect("Safe because if statement");

                    assert!(!fixed_fields.contains_key(&field));

                    for can_be in pos_can_be.iter_mut() {
                        can_be.remove(&field);
                    }

                    fixed_fields.insert(field, pos);
                }
            }

            // Reset can_fit
            can_fit.values_mut().for_each(|v| *v = 0);

            for (pos, candiates) in pos_can_be.iter().enumerate() {
                for candidate in candiates {
                    *can_fit.get_mut(candidate.as_str()).unwrap() |= 1 << pos;
                }
            }

            for (&field, &pos) in can_fit.iter().filter(|(_, v)| v.count_ones() == 1) {
                let pos = pos.trailing_zeros() as usize;
                assert!(!fixed_fields.contains_key(field));

                pos_can_be[pos].clear();

                fixed_fields.insert(field.to_owned(), pos);
            }
        }

        fixed_fields
            .iter()
            .filter(|(k, _)| k.starts_with("departure"))
            .map(|(_, &v)| my_ticket[v])
            .fold(1u64, |a, b| a * (b as u64))
            .to_string()
    }
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("../samples/16.txt");

    #[test]
    fn sample_part1() {
        test_implementation!(Day16, 1, SAMPLE, 71);
    }
}
<commit_msg>Even more bitsets<commit_after>use std::collections::HashMap;
use std::io::Read;
use std::ops::RangeInclusive;

use crate::common::Lines;
use crate::Solution;

fn split_nums<'a>(s: &'a str) -> impl Iterator<Item = u32> + 'a {
    s.split(|c: char| !c.is_ascii_digit()).filter_map(|s| {
        if s.is_empty() {
            None
        } else {
            Some(s.parse().unwrap())
        }
    })
}

fn read_input(input: &mut dyn Read) -> (HashMap<String, Vec<RangeInclusive<u32>>>, Vec<Vec<u32>>) {
    let mut lines = Lines::new(input).filter(|s| !s.is_empty());

    let mut rules = HashMap::new();
    let mut tickets = Vec::new();

    while let Some(line) = lines.next() {
        if line.as_str() == "your ticket:" {
            break;
        }

        let colon = line.find(':').unwrap();

        let nums: Vec<_> = split_nums(&line[colon..]).collect();

        let ranges: Vec<_> = nums.chunks_exact(2).map(|s| s[0]..=s[1]).collect();

        rules.insert(line[..colon].to_owned(), ranges);
    }

    for line in lines {
        if line.as_str() == "nearby tickets:" {
            continue;
        }

        tickets.push(split_nums(&line).collect());
    }

    (rules, tickets)
}

#[derive(Default)]
pub struct Day16;

impl Solution for Day16 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        let (rules, tickets) = read_input(input);

        let mut rate = 0;

        for ticket in &tickets[1..] {
            for value in ticket {
                if rules.values().flatten().all(|r| !r.contains(value)) {
                    rate += value;
                }
            }
        }

        rate.to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        let (rules, tickets) = read_input(input);
        let mut tickets = tickets;

        // Filter out invalid tickets
        tickets.retain(|t| {
            t.iter()
                .all(|v| rules.values().flatten().any(|r| r.contains(v)))
        });

        let fields: Vec<_> = rules.keys().collect();
        let ranges: Vec<_> = rules.values().collect();

        let my_ticket = &tickets[0];

        let mut pos_can_be = vec![(1u64 << fields.len()) - 1; my_ticket.len()];

        let mut fixed_fields = HashMap::new();

        for ticket in &tickets {
            for (r, &ranges) in ranges.iter().enumerate() {
                for (pos, value) in ticket.iter().enumerate() {
                    if pos_can_be[pos].count_ones() <= 1 {
                        continue;
                    }

                    if !ranges.iter().any(|r| r.contains(value)) {
                        pos_can_be[pos] &= !(1 << r);
                    }
                }
            }
        }

        let mut can_fit = vec![0u64; fields.len()];

        while fixed_fields.len() != rules.len() {
            // Fix fields that are the only option for a certain spot
            for pos in 0..pos_can_be.len() {
                if pos_can_be[pos].count_ones() == 1 {
                    let field_num = pos_can_be[pos].trailing_zeros();
                    let field = fields[field_num as usize];

                    assert!(!fixed_fields.contains_key(&field));

                    for can_be in pos_can_be.iter_mut() {
                        *can_be &= !(1 << field_num);
                    }

                    fixed_fields.insert(field, pos);
                }
            }

            for (r, candidates) in can_fit.iter_mut().enumerate() {
                *candidates = 0;
                let flag = 1 << r;

                for (pos, valid) in pos_can_be.iter().enumerate() {
                    if (valid & flag) != 0 {
                        *candidates |= 1 << pos;
                    }
                }
            }

            for (field, &pos) in can_fit
                .iter()
                .enumerate()
                .filter(|(_, v)| v.count_ones() == 1)
            {
                let pos = pos.trailing_zeros() as usize;
                let field = fields[field];
                assert!(!fixed_fields.contains_key(field));

                pos_can_be[pos] = 0;

                fixed_fields.insert(field, pos);
            }
        }

        fixed_fields
            .iter()
            .filter(|(k, _)| k.starts_with("departure"))
            .map(|(_, &v)| my_ticket[v])
            .fold(1u64, |a, b| a * (b as u64))
            .to_string()
    }
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("../samples/16.txt");

    #[test]
    fn sample_part1() {
        test_implementation!(Day16, 1, SAMPLE, 71);
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

// The benchmarks here verify that the complexity grows as O(*n*)
// where *n* is the number of characters in the text to be wrapped.

extern crate test;
extern crate lipsum;
extern crate textwrap;
#[cfg(feature = "hyphenation")]
extern crate hyphenation;

use test::Bencher;
#[cfg(feature = "hyphenation")]
use hyphenation::Language;
#[cfg(feature = "hyphenation")]
use textwrap::Wrapper;

const LINE_LENGTH: usize = 60;

/// Generate a lorem ipsum text with the given number of characters.
fn lorem_ipsum(length: usize) -> String {
    // The average word length in the lorem ipsum text is somewhere
    // between 6 and 7. So we conservatively divide by 5 to have a
    // long enough text that we can truncate below.
    let mut text = lipsum::lipsum(length / 5);
    text.truncate(length);
    text
}

#[bench]
fn lorem_100(b: &mut Bencher) {
    let text = &lorem_ipsum(100);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn lorem_200(b: &mut Bencher) {
    let text = &lorem_ipsum(200);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn lorem_400(b: &mut Bencher) {
    let text = &lorem_ipsum(400);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn lorem_800(b: &mut Bencher) {
    let text = &lorem_ipsum(800);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
#[cfg(feature = "hyphenation")]
fn hyphenation_lorem_100(b: &mut Bencher) {
    let text = &lorem_ipsum(100);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let wrapper = Wrapper::new(LINE_LENGTH).word_splitter(Box::new(corpus));
    b.iter(|| wrapper.fill(text))
}

#[bench]
#[cfg(feature = "hyphenation")]
fn hyphenation_lorem_200(b: &mut Bencher) {
    let text = &lorem_ipsum(200);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let wrapper = Wrapper::new(LINE_LENGTH).word_splitter(Box::new(corpus));
    b.iter(|| wrapper.fill(text))
}

#[bench]
#[cfg(feature = "hyphenation")]
fn hyphenation_lorem_400(b: &mut Bencher) {
    let text = &lorem_ipsum(400);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let wrapper = Wrapper::new(LINE_LENGTH).word_splitter(Box::new(corpus));
    b.iter(|| wrapper.fill(text))
}

#[bench]
#[cfg(feature = "hyphenation")]
fn hyphenation_lorem_800(b: &mut Bencher) {
    let text = &lorem_ipsum(800);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let wrapper = Wrapper::new(LINE_LENGTH).word_splitter(Box::new(corpus));
    b.iter(|| wrapper.fill(text))
}
<commit_msg>benches: rename benchmarks to indicate type<commit_after>#![feature(test)]

// The benchmarks here verify that the complexity grows as O(*n*)
// where *n* is the number of characters in the text to be wrapped.

extern crate test;
extern crate lipsum;
extern crate textwrap;
#[cfg(feature = "hyphenation")]
extern crate hyphenation;

use test::Bencher;
#[cfg(feature = "hyphenation")]
use hyphenation::Language;
#[cfg(feature = "hyphenation")]
use textwrap::Wrapper;

const LINE_LENGTH: usize = 60;

/// Generate a lorem ipsum text with the given number of characters.
fn lorem_ipsum(length: usize) -> String {
    // The average word length in the lorem ipsum text is somewhere
    // between 6 and 7. So we conservatively divide by 5 to have a
    // long enough text that we can truncate below.
    let mut text = lipsum::lipsum(length / 5);
    text.truncate(length);
    text
}

#[bench]
fn fill_100(b: &mut Bencher) {
    let text = &lorem_ipsum(100);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn fill_200(b: &mut Bencher) {
    let text = &lorem_ipsum(200);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn fill_400(b: &mut Bencher) {
    let text = &lorem_ipsum(400);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn fill_800(b: &mut Bencher) {
    let text = &lorem_ipsum(800);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
#[cfg(feature = "hyphenation")]
fn hyphenation_fill_100(b: &mut Bencher) {
    let text = &lorem_ipsum(100);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let wrapper = Wrapper::new(LINE_LENGTH).word_splitter(Box::new(corpus));
    b.iter(|| wrapper.fill(text))
}

#[bench]
#[cfg(feature = "hyphenation")]
fn hyphenation_fill_200(b: &mut Bencher) {
    let text = &lorem_ipsum(200);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let wrapper = Wrapper::new(LINE_LENGTH).word_splitter(Box::new(corpus));
    b.iter(|| wrapper.fill(text))
}

#[bench]
#[cfg(feature = "hyphenation")]
fn hyphenation_fill_400(b: &mut Bencher) {
    let text = &lorem_ipsum(400);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let wrapper = Wrapper::new(LINE_LENGTH).word_splitter(Box::new(corpus));
    b.iter(|| wrapper.fill(text))
}

#[bench]
#[cfg(feature = "hyphenation")]
fn hyphenation_fill_800(b: &mut Bencher) {
    let text = &lorem_ipsum(800);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let wrapper = Wrapper::new(LINE_LENGTH).word_splitter(Box::new(corpus));
    b.iter(|| wrapper.fill(text))
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, Arg, ErrorKind, ArgGroup};

static CONFLICT_ERR: &'static str = "error: The argument '-F' cannot be used with '--flag'

USAGE:
    clap-test <positional> <positional2> --flag --long-option-2 <option2>

For more information try --help";

static CONFLICT_ERR_REV: &'static str = "error: The argument '--flag' cannot be used with '-F'

USAGE:
    clap-test <positional> <positional2> -F --long-option-2 <option2>

For more information try --help";

#[test]
fn flag_conflict() {
    let result = App::new("flag_conflict")
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("other"))
        .arg(Arg::from_usage("-o, --other 'some flag'"))
        .get_matches_from_safe(vec!["myprog", "-f", "-o"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn flag_conflict_2() {
    let result = App::new("flag_conflict")
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("other"))
        .arg(Arg::from_usage("-o, --other 'some flag'"))
        .get_matches_from_safe(vec!["myprog", "-o", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_conflict() {
    let result = App::new("group_conflict")
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("gr"))
        .group(ArgGroup::with_name("gr")
            .required(true)
            .arg("some")
            .arg("other"))
        .arg(Arg::from_usage("--some 'some arg'"))
        .arg(Arg::from_usage("--other 'other arg'"))
        .get_matches_from_safe(vec!["myprog", "--other", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_conflict_2() {
    let result = App::new("group_conflict")
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("gr"))
        .group(ArgGroup::with_name("gr")
            .required(true)
            .arg("some")
            .arg("other"))
        .arg(Arg::from_usage("--some 'some arg'"))
        .arg(Arg::from_usage("--other 'other arg'"))
        .get_matches_from_safe(vec!["myprog", "-f", "--some"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn conflict_output() {
    test::compare_output(test::complex_app(), "clap-test val1 --flag --long-option-2 val2 -F", CONFLICT_ERR, true);
}

#[test]
fn conflict_output_rev() {
    test::compare_output(test::complex_app(), "clap-test val1 -F --long-option-2 val2 --flag", CONFLICT_ERR_REV, true);
}
<commit_msg>tests: adds tests to make sure args with default values can have conflicts<commit_after>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, Arg, ErrorKind, ArgGroup};

static CONFLICT_ERR: &'static str = "error: The argument '-F' cannot be used with '--flag'

USAGE:
    clap-test <positional> <positional2> --flag --long-option-2 <option2>

For more information try --help";

static CONFLICT_ERR_REV: &'static str = "error: The argument '--flag' cannot be used with '-F'

USAGE:
    clap-test <positional> <positional2> -F --long-option-2 <option2>

For more information try --help";

#[test]
fn flag_conflict() {
    let result = App::new("flag_conflict")
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("other"))
        .arg(Arg::from_usage("-o, --other 'some flag'"))
        .get_matches_from_safe(vec!["myprog", "-f", "-o"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn flag_conflict_2() {
    let result = App::new("flag_conflict")
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("other"))
        .arg(Arg::from_usage("-o, --other 'some flag'"))
        .get_matches_from_safe(vec!["myprog", "-o", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_conflict() {
    let result = App::new("group_conflict")
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("gr"))
        .group(ArgGroup::with_name("gr")
            .required(true)
            .arg("some")
            .arg("other"))
        .arg(Arg::from_usage("--some 'some arg'"))
        .arg(Arg::from_usage("--other 'other arg'"))
        .get_matches_from_safe(vec!["myprog", "--other", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_conflict_2() {
    let result = App::new("group_conflict")
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("gr"))
        .group(ArgGroup::with_name("gr")
            .required(true)
            .arg("some")
            .arg("other"))
        .arg(Arg::from_usage("--some 'some arg'"))
        .arg(Arg::from_usage("--other 'other arg'"))
        .get_matches_from_safe(vec!["myprog", "-f", "--some"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn conflict_output() {
    test::compare_output(test::complex_app(), "clap-test val1 --flag --long-option-2 val2 -F", CONFLICT_ERR, true);
}

#[test]
fn conflict_output_rev() {
    test::compare_output(test::complex_app(), "clap-test val1 -F --long-option-2 val2 --flag", CONFLICT_ERR_REV, true);
}

#[test]
fn conflict_with_unused_default_value() {
    let result = App::new("conflict")
        .arg(Arg::from_usage("-o, --opt=[opt] 'some opt'")
            .default_value("default"))
        .arg(Arg::from_usage("-f, --flag 'some flag'")
            .conflicts_with("opt"))
        .get_matches_from_safe(vec!["myprog", "-f"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert_eq!(m.value_of("opt"), Some("default"));
    assert!(m.is_present("flag"));
}
<|endoftext|>


<commit_before>use actix_web::{http::StatusCode, server};
use env_logger;
use potboiler;
use potboiler_common::{pg, server_id, test::ServerThread};
use regex::Regex;
use reqwest::{header, Client};
use serde_json::json;
use serial_test_derive::serial;
use std::{env, str};
use thiserror::Error;

#[derive(Debug, Error)]
enum IntegrationError {
    #[error("IoError")]
    IoError {
        #[source]
        cause: std::io::Error,
    },
}

fn boot_potboiler() -> Result<ServerThread> {
    let _ = env_logger::try_init();
    let pool = potboiler::db_setup()?;
    let app_state = potboiler::AppState::new(pool, server_id::test()).unwrap();
    return ServerThread::new({
        move || server::new(move || potboiler::app_router(app_state.clone()).unwrap()).bind("0.0.0.0:8000")
    })
    .map_err(|e| IntegrationError::IoError { cause: e }.into());
}

fn test_setup() -> Result<(ServerThread, ServerThread)> {
    let _ = env_logger::try_init();
    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = pg::get_pool(db_url).unwrap();
    pool.wipe_db()?;
    let pb_server = boot_potboiler()?;
    env::set_var("SERVER_URL", "http://localhost:8000/log");
    env::set_var("PORT", "8001");
    let app_state = pigtail::AppState::new(pool)?;
    let pigtail_server = ServerThread::new({
        move || server::new(move || pigtail::app_router(app_state.clone()).unwrap()).bind("0.0.0.0:8001")
    })?;
    pigtail::register();
    return Ok((pb_server, pigtail_server));
}

#[test]
#[serial]
fn test_create_queue() {
    let (_pb_server, _pigtail_server) = test_setup().unwrap();
    let client = Client::new();
    let response = client
        .post("http://localhost:8001/create")
        .json(&json!({"name":"foo", "timeout_ms": 1000}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
}

#[test]
#[serial]
fn test_add_entry() {
    let (_pb_server, _pigtail_server) = test_setup().unwrap();
    let client = Client::new();
    let mut response = client
        .post("http://localhost:8001/create")
        .json(&json!({"name":"foo", "timeout_ms": 1000}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
    response = client
        .post("http://localhost:8001/queue/foo")
        .json(&json!({"task_name":"hello_world", "info":{"foo":"bar"}}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
    let re = Regex::new(r"/queue/foo/([a-z0-9-]+)").unwrap();
    let location = format!("{:?}", response.headers()[header::LOCATION]);
    assert!(re.is_match(&location), location);
}
<commit_msg>Fix pigtail test Result usage<commit_after>use actix_web::{http::StatusCode, server};
use anyhow::Result;
use env_logger;
use potboiler;
use potboiler_common::{pg, server_id, test::ServerThread};
use regex::Regex;
use reqwest::{header, Client};
use serde_json::json;
use serial_test_derive::serial;
use std::{env, str};
use thiserror::Error;

#[derive(Debug, Error)]
enum IntegrationError {
    #[error("IoError")]
    IoError {
        #[source]
        cause: std::io::Error,
    },
}

fn boot_potboiler() -> Result<ServerThread> {
    let _ = env_logger::try_init();
    let pool = potboiler::db_setup()?;
    let app_state = potboiler::AppState::new(pool, server_id::test()).unwrap();
    return ServerThread::new({
        move || server::new(move || potboiler::app_router(app_state.clone()).unwrap()).bind("0.0.0.0:8000")
    })
    .map_err(|e| IntegrationError::IoError { cause: e }.into());
}

fn test_setup() -> Result<(ServerThread, ServerThread)> {
    let _ = env_logger::try_init();
    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = pg::get_pool(db_url).unwrap();
    pool.wipe_db()?;
    let pb_server = boot_potboiler()?;
    env::set_var("SERVER_URL", "http://localhost:8000/log");
    env::set_var("PORT", "8001");
    let app_state = pigtail::AppState::new(pool)?;
    let pigtail_server = ServerThread::new({
        move || server::new(move || pigtail::app_router(app_state.clone()).unwrap()).bind("0.0.0.0:8001")
    })?;
    pigtail::register();
    return Ok((pb_server, pigtail_server));
}

#[test]
#[serial]
fn test_create_queue() {
    let (_pb_server, _pigtail_server) = test_setup().unwrap();
    let client = Client::new();
    let response = client
        .post("http://localhost:8001/create")
        .json(&json!({"name":"foo", "timeout_ms": 1000}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
}

#[test]
#[serial]
fn test_add_entry() {
    let (_pb_server, _pigtail_server) = test_setup().unwrap();
    let client = Client::new();
    let mut response = client
        .post("http://localhost:8001/create")
        .json(&json!({"name":"foo", "timeout_ms": 1000}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
    response = client
        .post("http://localhost:8001/queue/foo")
        .json(&json!({"task_name":"hello_world", "info":{"foo":"bar"}}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
    let re = Regex::new(r"/queue/foo/([a-z0-9-]+)").unwrap();
    let location = format!("{:?}", response.headers()[header::LOCATION]);
    assert!(re.is_match(&location), location);
}
<|endoftext|>


<commit_before>// Copyright 2017 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

use std::io::stdin;

use linefeed::{
    DefaultTerminal,
    Reader,
    ReadResult,
    Signal,
};

use termion::{
    color,
};

use self::InputResult::*;

use command_parser::{
    Command,
    command,
};

use failure::Error;

/// Starting prompt
const DEFAULT_PROMPT: &'static str = "mentat=> ";
/// Prompt when further input is being read
// TODO: Should this actually reflect the current open brace?
const MORE_PROMPT: &'static str = "mentat.> ";

/// Possible results from reading input from `InputReader`
#[derive(Clone, Debug)]
pub enum InputResult {
    /// mentat command as input; (name, rest of line)
    MetaCommand(Command),
    /// An empty line
    Empty,
    /// Needs more input
    More,
    /// End of file reached
    Eof,
}

/// Reads input from `stdin`
pub struct InputReader {
    buffer: String,
    reader: Option<Reader<DefaultTerminal>>,
    in_process_cmd: Option<Command>,
}

enum UserAction {
    // We've received some text that we should interpret as a new command, or
    // as part of the current command.
    TextInput(String),
    // We were interrupted, if we have a current command we should clear it,
    // otherwise we should exit. Currently can only be generated by reading from
    // a terminal (and not by reading from stdin).
    Interrupt,
    // We hit the end of the file, there was an error getting user input, or
    // something else happened that means we should exit.
    Quit,
}

impl InputReader {
    /// Constructs a new `InputReader` reading from `stdin`.
    pub fn new() -> InputReader {
        let r = match Reader::new("mentat") {
            Ok(mut r) => {
                // Handle SIGINT (Ctrl-C)
                r.set_report_signal(Signal::Interrupt, true);
                r.set_word_break_chars(" \t\n!\"#$%&'(){}*+,-./:;<=>?@[\\]^`");
                Some(r)
            },
            Err(_) => None,
        };

        InputReader{
            buffer: String::new(),
            reader: r,
            in_process_cmd: None,
        }
    }

    /// Returns whether the `InputReader` is reading from a TTY.
    pub fn is_tty(&self) -> bool {
        self.reader.is_some()
    }

    /// Reads a single command, item, or statement from `stdin`.
    /// Returns `More` if further input is required for a complete result.
    /// In this case, the input received so far is buffered internally.
    pub fn read_input(&mut self) -> Result<InputResult, Error> {
        let prompt = if self.in_process_cmd.is_some() { MORE_PROMPT } else { DEFAULT_PROMPT };
        let prompt = format!("{blue}{prompt}{reset}",
                             blue = color::Fg(::BLUE),
                             prompt = prompt,
                             reset = color::Fg(color::Reset));
        let line = match self.read_line(prompt.as_str()) {
            UserAction::TextInput(s) => s,
            UserAction::Interrupt if self.in_process_cmd.is_some() => {
                self.in_process_cmd = None;
                self.buffer.clear();
                // Move to the next line, so that our next prompt isn't on top
                // of the previous.
                println!();
                String::new()
            },
            _ => return Ok(Eof),
        };

        if !self.buffer.is_empty() {
            self.buffer.push('\n');
        }

        self.buffer.push_str(&line);

        if self.buffer.is_empty() {
            return Ok(Empty);
        }

        // if we have a command in process (i.e. an incomplete query or transaction),
        // then we already know which type of command it is and so we don't need to parse the
        // command again, only the content, which we do later.
        // Therefore, we add the newly read in line to the existing command args.
        // If there is no in process command, we parse the read in line as a new command.
        let cmd = match &self.in_process_cmd {
            &Some(Command::QueryPrepared(ref args)) => {
                Ok(Command::QueryPrepared(args.clone() + " " + &line))
            },
            &Some(Command::Query(ref args)) => {
                Ok(Command::Query(args.clone() + " " + &line))
            },
            &Some(Command::Transact(ref args)) => {
                Ok(Command::Transact(args.clone() + " " + &line))
            },
            _ => {
                command(&self.buffer)
            },
        };

        match cmd {
            Ok(cmd) => {
                match cmd {
                    Command::Query(_) |
                    Command::QueryPrepared(_) |
                    Command::Transact(_) |
                    Command::QueryExplain(_) if !cmd.is_complete() => {
                        // A query or transact is complete if it contains a valid EDN.
                        // if the command is not complete, ask for more from the REPL and remember
                        // which type of command we've found here.
                        self.in_process_cmd = Some(cmd);
                        Ok(More)
                    },
                    _ => {
                        let entry = self.buffer.clone();
                        self.buffer.clear();
                        self.add_history(entry);
                        self.in_process_cmd = None;
                        Ok(InputResult::MetaCommand(cmd))
                    }
                }
            },
            Err(e) => {
                let entry = self.buffer.clone();
                self.buffer.clear();
                self.add_history(entry);
                self.in_process_cmd = None;
                Err(e)
            },
        }
    }

    fn read_line(&mut self, prompt: &str) -> UserAction {
        match self.reader {
            Some(ref mut r) => {
                r.set_prompt(prompt);
                r.read_line().ok().map_or(UserAction::Quit, |line|
                    match line {
                        ReadResult::Input(s) => UserAction::TextInput(s),
                        ReadResult::Signal(Signal::Interrupt) =>
                            UserAction::Interrupt,
                        _ => UserAction::Quit,
                    })

            },
            None => self.read_stdin()
        }
    }

    fn read_stdin(&self) -> UserAction {
        let mut s = String::new();

        match stdin().read_line(&mut s) {
            Ok(0) | Err(_) => UserAction::Quit,
            Ok(_) => UserAction::TextInput(s)
        }
    }

    fn add_history(&mut self, line: String) {
        if let Some(ref mut r) = self.reader {
            r.add_history(line);
        }
    }
}
<commit_msg>[cli] Handle line comments in EDN input. (#759) (#761) r=grisha<commit_after>// Copyright 2017 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

use std::io::stdin;

use linefeed::{
    DefaultTerminal,
    Reader,
    ReadResult,
    Signal,
};

use termion::{
    color,
};

use self::InputResult::*;

use command_parser::{
    Command,
    command,
};

use failure::Error;

/// Starting prompt
const DEFAULT_PROMPT: &'static str = "mentat=> ";
/// Prompt when further input is being read
// TODO: Should this actually reflect the current open brace?
const MORE_PROMPT: &'static str = "mentat.> ";

/// Possible results from reading input from `InputReader`
#[derive(Clone, Debug)]
pub enum InputResult {
    /// mentat command as input; (name, rest of line)
    MetaCommand(Command),
    /// An empty line
    Empty,
    /// Needs more input
    More,
    /// End of file reached
    Eof,
}

/// Reads input from `stdin`
pub struct InputReader {
    buffer: String,
    reader: Option<Reader<DefaultTerminal>>,
    in_process_cmd: Option<Command>,
}

enum UserAction {
    // We've received some text that we should interpret as a new command, or
    // as part of the current command.
    TextInput(String),
    // We were interrupted, if we have a current command we should clear it,
    // otherwise we should exit. Currently can only be generated by reading from
    // a terminal (and not by reading from stdin).
    Interrupt,
    // We hit the end of the file, there was an error getting user input, or
    // something else happened that means we should exit.
    Quit,
}

impl InputReader {
    /// Constructs a new `InputReader` reading from `stdin`.
    pub fn new() -> InputReader {
        let r = match Reader::new("mentat") {
            Ok(mut r) => {
                // Handle SIGINT (Ctrl-C)
                r.set_report_signal(Signal::Interrupt, true);
                r.set_word_break_chars(" \t\n!\"#$%&'(){}*+,-./:;<=>?@[\\]^`");
                Some(r)
            },
            Err(_) => None,
        };

        InputReader{
            buffer: String::new(),
            reader: r,
            in_process_cmd: None,
        }
    }

    /// Returns whether the `InputReader` is reading from a TTY.
    pub fn is_tty(&self) -> bool {
        self.reader.is_some()
    }

    /// Reads a single command, item, or statement from `stdin`.
    /// Returns `More` if further input is required for a complete result.
    /// In this case, the input received so far is buffered internally.
    pub fn read_input(&mut self) -> Result<InputResult, Error> {
        let prompt = if self.in_process_cmd.is_some() { MORE_PROMPT } else { DEFAULT_PROMPT };
        let prompt = format!("{blue}{prompt}{reset}",
                             blue = color::Fg(::BLUE),
                             prompt = prompt,
                             reset = color::Fg(color::Reset));
        let line = match self.read_line(prompt.as_str()) {
            UserAction::TextInput(s) => s,
            UserAction::Interrupt if self.in_process_cmd.is_some() => {
                self.in_process_cmd = None;
                self.buffer.clear();
                // Move to the next line, so that our next prompt isn't on top
                // of the previous.
                println!();
                String::new()
            },
            _ => return Ok(Eof),
        };

        if !self.buffer.is_empty() {
            self.buffer.push('\n');
        }

        self.buffer.push_str(&line);

        if self.buffer.is_empty() {
            return Ok(Empty);
        }

        // if we have a command in process (i.e. an incomplete query or transaction),
        // then we already know which type of command it is and so we don't need to parse the
        // command again, only the content, which we do later.
        // Therefore, we add the newly read in line to the existing command args.
        // If there is no in process command, we parse the read in line as a new command.
        let cmd = match &self.in_process_cmd {
            &Some(Command::QueryPrepared(ref args)) => {
                Ok(Command::QueryPrepared(args.clone() + "\n" + &line))
            },
            &Some(Command::Query(ref args)) => {
                Ok(Command::Query(args.clone() + "\n" + &line))
            },
            &Some(Command::Transact(ref args)) => {
                Ok(Command::Transact(args.clone() + "\n" + &line))
            },
            _ => {
                command(&self.buffer)
            },
        };

        match cmd {
            Ok(cmd) => {
                match cmd {
                    Command::Query(_) |
                    Command::QueryPrepared(_) |
                    Command::Transact(_) |
                    Command::QueryExplain(_) if !cmd.is_complete() => {
                        // A query or transact is complete if it contains a valid EDN.
                        // if the command is not complete, ask for more from the REPL and remember
                        // which type of command we've found here.
                        self.in_process_cmd = Some(cmd);
                        Ok(More)
                    },
                    _ => {
                        let entry = self.buffer.clone();
                        self.buffer.clear();
                        self.add_history(entry);
                        self.in_process_cmd = None;
                        Ok(InputResult::MetaCommand(cmd))
                    }
                }
            },
            Err(e) => {
                let entry = self.buffer.clone();
                self.buffer.clear();
                self.add_history(entry);
                self.in_process_cmd = None;
                Err(e)
            },
        }
    }

    fn read_line(&mut self, prompt: &str) -> UserAction {
        match self.reader {
            Some(ref mut r) => {
                r.set_prompt(prompt);
                r.read_line().ok().map_or(UserAction::Quit, |line|
                    match line {
                        ReadResult::Input(s) => UserAction::TextInput(s),
                        ReadResult::Signal(Signal::Interrupt) =>
                            UserAction::Interrupt,
                        _ => UserAction::Quit,
                    })

            },
            None => self.read_stdin()
        }
    }

    fn read_stdin(&self) -> UserAction {
        let mut s = String::new();

        match stdin().read_line(&mut s) {
            Ok(0) | Err(_) => UserAction::Quit,
            Ok(_) => UserAction::TextInput(s)
        }
    }

    fn add_history(&mut self, line: String) {
        if let Some(ref mut r) = self.reader {
            r.add_history(line);
        }
    }
}
<|endoftext|>


<commit_before>extern crate shrust;
extern crate clap;
extern crate rustc_serialize;
extern crate itertools;
extern crate libcobra;

mod interpreter;
mod debugger;
mod value;
mod valueref;
#[cfg(test)]
mod tests;

use std::fs::File;
use std::process::exit;
use clap::{App, Arg};
use libcobra::bytecode::{ByteCodeModule, START_CODE_FUNCTION};
use interpreter::{ExecutionError, run_byte_code};
use debugger::debug_byte_code;

#[derive(RustcDecodable, Debug)]
struct Args
{
    arg_bytecode_file: Option<String>,
    flag_debug: Option<bool>,
}

fn run() -> Result<i32, ExecutionError>
{
    let matches = App::new("cobrai")
        .version("0.1")
        .author("Joris Guisson <joris.guisson@gmail.com>")
        .about("cobra language interpreter")
        .arg(Arg::with_name("debug")
            .short("d")
            .long("debug")
            .help("Run the interpreter in debug mode"))
        .arg(Arg::with_name("bytecode-file")
            .help("Bytecode file to run")
            .required(true)
            .index(1))
        .get_matches();

    let bytecode_file = matches.value_of("bytecode-file").expect("Missing input file argument");
    let run_debugger = matches.is_present("debug");

    let mut file = File::open(&bytecode_file)
        .map_err(|err| ExecutionError(format!("Cannot open {}: {}", bytecode_file, err)))?;

    let bc_mod = ByteCodeModule::load(&mut file)
        .map_err(|err| ExecutionError(err))?;

    let ret = if run_debugger {
        debug_byte_code(&bc_mod, START_CODE_FUNCTION)?
    } else {
        run_byte_code(&bc_mod, START_CODE_FUNCTION)?
    };

    Ok(ret.to_exit_code())
}

fn main()
{
    match run()
    {
        Ok(ret) => {
            exit(ret)
        },
        Err(e) => {
            println!("Failed to execute program: {}", e.0);
            exit(-1)
        }
    }
}
<commit_msg>Remove old Arg struct<commit_after>extern crate shrust;
extern crate clap;
extern crate rustc_serialize;
extern crate itertools;
extern crate libcobra;

mod interpreter;
mod debugger;
mod value;
mod valueref;
#[cfg(test)]
mod tests;

use std::fs::File;
use std::process::exit;
use clap::{App, Arg};
use libcobra::bytecode::{ByteCodeModule, START_CODE_FUNCTION};
use interpreter::{ExecutionError, run_byte_code};
use debugger::debug_byte_code;

fn run() -> Result<i32, ExecutionError>
{
    let matches = App::new("cobrai")
        .version("0.1")
        .author("Joris Guisson <joris.guisson@gmail.com>")
        .about("cobra language interpreter")
        .arg(Arg::with_name("debug")
            .short("d")
            .long("debug")
            .help("Run the interpreter in debug mode"))
        .arg(Arg::with_name("bytecode-file")
            .help("Bytecode file to run")
            .required(true)
            .index(1))
        .get_matches();

    let bytecode_file = matches.value_of("bytecode-file").expect("Missing input file argument");
    let run_debugger = matches.is_present("debug");

    let mut file = File::open(&bytecode_file)
        .map_err(|err| ExecutionError(format!("Cannot open {}: {}", bytecode_file, err)))?;

    let bc_mod = ByteCodeModule::load(&mut file)
        .map_err(|err| ExecutionError(err))?;

    let ret = if run_debugger {
        debug_byte_code(&bc_mod, START_CODE_FUNCTION)?
    } else {
        run_byte_code(&bc_mod, START_CODE_FUNCTION)?
    };

    Ok(ret.to_exit_code())
}

fn main()
{
    match run()
    {
        Ok(ret) => {
            exit(ret)
        },
        Err(e) => {
            println!("Failed to execute program: {}", e.0);
            exit(-1)
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use std::str::FromStr;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let code = "..100u32";
    let tt = TokenStream::from_str(code).unwrap();
    let expr: Expr = syn::parse2(tt.clone()).unwrap();
    let expr_range: ExprRange = syn::parse2(tt).unwrap();
    assert_eq!(expr, Expr::Range(expr_range));
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let expr = syn::parse_str::<Expr>("fut.await").unwrap();

    snapshot!(expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);

    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
        TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        attrs: [
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "outside",
                            arguments: None,
                        },
                    ],
                },
                tokens: TokenStream(``),
            },
        ],
        func: Expr::Group {
            expr: Expr::Path {
                attrs: [
                    Attribute {
                        style: Outer,
                        path: Path {
                            segments: [
                                PathSegment {
                                    ident: "inside",
                                    arguments: None,
                                },
                            ],
                        },
                        tokens: TokenStream(``),
                    },
                ],
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_macro() {
    // mimics the token stream corresponding to `$macro!()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { m })),
        TokenTree::Punct(Punct::new('!', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Macro {
        mac: Macro {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "m",
                        arguments: None,
                    },
                ],
            },
            delimiter: Paren,
            tokens: TokenStream(``),
        },
    }
    "###);
}

#[test]
fn test_macro_variable_struct() {
    // mimics the token stream corresponding to `$struct {}`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { S })),
        TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Struct {
        path: Path {
            segments: [
                PathSegment {
                    ident: "S",
                    arguments: None,
                },
            ],
        },
    }
    "###);
}

#[test]
fn test_macro_variable_match_arm() {
    // mimics the token stream corresponding to `match v { _ => $expr }`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("match", Span::call_site())),
        TokenTree::Ident(Ident::new("v", Span::call_site())),
        TokenTree::Group(Group::new(
            Delimiter::Brace,
            TokenStream::from_iter(vec![
                TokenTree::Punct(Punct::new('_', Spacing::Alone)),
                TokenTree::Punct(Punct::new('=', Spacing::Joint)),
                TokenTree::Punct(Punct::new('>', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::None, quote! { #[a] () })),
            ]),
        )),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Match {
        expr: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "v",
                        arguments: None,
                    },
                ],
            },
        },
        arms: [
            Arm {
                pat: Pat::Wild,
                body: Expr::Group {
                    expr: Expr::Tuple {
                        attrs: [
                            Attribute {
                                style: Outer,
                                path: Path {
                                    segments: [
                                        PathSegment {
                                            ident: "a",
                                            arguments: None,
                                        },
                                    ],
                                },
                                tokens: TokenStream(``),
                            },
                        ],
                    },
                },
            },
        ],
    }
    "###);
}
<commit_msg>Consistently use tokens and snapshots in test_expr<commit_after>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let tokens = quote!(..100u32);
    snapshot!(tokens as Expr, @r###"
    Expr::Range {
        limits: HalfOpen,
        to: Some(Expr::Lit {
            lit: 100u32,
        }),
    }
    "###);

    let tokens = quote!(..100u32);
    snapshot!(tokens as ExprRange, @r###"
    ExprRange {
        limits: HalfOpen,
        to: Some(Expr::Lit {
            lit: 100u32,
        }),
    }
    "###);
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let tokens = quote!(fut.await);

    snapshot!(tokens as Expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);

    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
        TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        attrs: [
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "outside",
                            arguments: None,
                        },
                    ],
                },
                tokens: TokenStream(``),
            },
        ],
        func: Expr::Group {
            expr: Expr::Path {
                attrs: [
                    Attribute {
                        style: Outer,
                        path: Path {
                            segments: [
                                PathSegment {
                                    ident: "inside",
                                    arguments: None,
                                },
                            ],
                        },
                        tokens: TokenStream(``),
                    },
                ],
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_macro() {
    // mimics the token stream corresponding to `$macro!()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { m })),
        TokenTree::Punct(Punct::new('!', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Macro {
        mac: Macro {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "m",
                        arguments: None,
                    },
                ],
            },
            delimiter: Paren,
            tokens: TokenStream(``),
        },
    }
    "###);
}

#[test]
fn test_macro_variable_struct() {
    // mimics the token stream corresponding to `$struct {}`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { S })),
        TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Struct {
        path: Path {
            segments: [
                PathSegment {
                    ident: "S",
                    arguments: None,
                },
            ],
        },
    }
    "###);
}

#[test]
fn test_macro_variable_match_arm() {
    // mimics the token stream corresponding to `match v { _ => $expr }`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("match", Span::call_site())),
        TokenTree::Ident(Ident::new("v", Span::call_site())),
        TokenTree::Group(Group::new(
            Delimiter::Brace,
            TokenStream::from_iter(vec![
                TokenTree::Punct(Punct::new('_', Spacing::Alone)),
                TokenTree::Punct(Punct::new('=', Spacing::Joint)),
                TokenTree::Punct(Punct::new('>', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::None, quote! { #[a] () })),
            ]),
        )),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Match {
        expr: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "v",
                        arguments: None,
                    },
                ],
            },
        },
        arms: [
            Arm {
                pat: Pat::Wild,
                body: Expr::Group {
                    expr: Expr::Tuple {
                        attrs: [
                            Attribute {
                                style: Outer,
                                path: Path {
                                    segments: [
                                        PathSegment {
                                            ident: "a",
                                            arguments: None,
                                        },
                                    ],
                                },
                                tokens: TokenStream(``),
                            },
                        ],
                    },
                },
            },
        ],
    }
    "###);
}
<|endoftext|>


<commit_before>/**
 * 4.2 Pattern matching
 * http://static.rust-lang.org/doc/master/tutorial.html#pattern-matching
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */
use std::rand::{task_rng, Rng};
use std::f64;
use std::num::atan;
fn angle(vector: (f64, f64)) -> f64 {
	let pi = f64::consts::PI;
	/*
	 * A powerful application of pattern matching is destructuring:
	 * matching in order to bind names to the contents of data types.
	 */
	match vector {
		(0.0, y) if y < 0.0 => 1.5 * pi,
		(0.0, _) => 0.5 * pi,
		(x, y) => atan(y / x)
	}
}
fn main() {
	let mut rng = task_rng();
	let my_number: uint = rng.gen_range(0u, 10);
	println!("my_number = {}", my_number);

	/*
	 * Rust's match construct is a generalized, cleaned-up version of C's
	 * switch construct. You provide it with a value and a number of arms,
	 * each labelled with a pattern, and the code compares the value
	 * against each pattern in order until one matches. The matching
	 * pattern executes its corresponding arm.
	 */
	match my_number {
		0     => println!("zero"),
		1 | 2 => println!("one or two"),
		3..10 => println!("three to ten"),
		_     => println!("something else")
	}
	/*
	 * match constructs must be exhaustive: they must have an arm covering
	 * every possible case. For example, the typechecker would reject the
	 * previous example if the arm with the wildcard pattern was omitted.
	 */
	match my_number {
		0 => { println!("zero") }
		_ => { println!("something else") }
	}

	let age: uint = rng.gen_range(0u, 100);
	println!("age = {}", age);
	match age {
		a @ 0..20 => println!("{} years old", a),
		_ => println!("older than 21")
	}

	let vector = (1f64,1f64);
	println!("angle({:?}) == {:?}", vector, angle(vector));
}
<commit_msg>Add new code<commit_after>/**
 * 4.2 Pattern matching
 * http://static.rust-lang.org/doc/master/tutorial.html#pattern-matching
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */
use std::rand::{task_rng, Rng};
use std::f64;
use std::num::atan;
struct Point { x: f64, y: f64 }

fn angle(vector: (f64, f64)) -> f64 {
	let pi = f64::consts::PI;
	/*
	 * A powerful application of pattern matching is destructuring:
	 * matching in order to bind names to the contents of data types.
	 */
	match vector {
		(0.0, y) if y < 0.0 => 1.5 * pi,
		(0.0, _) => 0.5 * pi,
		(x, y) => atan(y / x)
	}
}
fn main() {
	let mut rng = task_rng();
	let my_number: uint = rng.gen_range(0u, 10);
	println!("my_number = {}", my_number);

	/*
	 * Rust's match construct is a generalized, cleaned-up version of C's
	 * switch construct. You provide it with a value and a number of arms,
	 * each labelled with a pattern, and the code compares the value
	 * against each pattern in order until one matches. The matching
	 * pattern executes its corresponding arm.
	 */
	match my_number {
		0     => println!("zero"),
		1 | 2 => println!("one or two"),
		3..10 => println!("three to ten"),
		_     => println!("something else")
	}
	/*
	 * match constructs must be exhaustive: they must have an arm covering
	 * every possible case. For example, the typechecker would reject the
	 * previous example if the arm with the wildcard pattern was omitted.
	 */
	match my_number {
		0 => { println!("zero") }
		_ => { println!("something else") }
	}

	let age: uint = rng.gen_range(0u, 100);
	println!("age = {}", age);
	match age {
		a @ 0..20 => println!("{} years old", a),
		_ => println!("older than 21")
	}

	let vector = (1f64,1f64);
	println!("angle({:?}) == {:?}", vector, angle(vector));

	/*
	 * To destructure a struct, use `..`.
	 * http://static.rust-lang.org/doc/master/tutorial.html#structs
	 */
	let mypoint = Point { x: 0.0, y: 0.0 };
	match mypoint {
		Point { x, .. } => println!("{}", x),
	}
}
<|endoftext|>


<commit_before>//! Runtime services
//!
//! The `rt` module provides a narrow set of runtime services,
//! including the global heap (exported in `heap`) and unwinding and
//! backtrace support. The APIs in this module are highly unstable,
//! and should be considered as private implementation details for the
//! time being.

#![unstable(
    feature = "rt",
    reason = "this public module should not exist and is highly likely \
              to disappear",
    issue = "none"
)]
#![doc(hidden)]

// Re-export some of our utilities which are expected by other crates.
pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
pub use core::panicking::panic_display;

// To reduce the generated code of the new `lang_start`, this function is doing
// the real work.
#[cfg(not(test))]
fn lang_start_internal(
    main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
    argc: isize,
    argv: *const *const u8,
) -> Result<isize, !> {
    use crate::{mem, panic, sys, sys_common};
    let rt_abort = move |e| {
        mem::forget(e);
        rtabort!("initialization or cleanup bug");
    };
    // Guard against the code called by this function from unwinding outside of the Rust-controlled
    // code, which is UB. This is a requirement imposed by a combination of how the
    // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
    // mechanism itself.
    //
    // There are a couple of instances where unwinding can begin. First is inside of the
    // `rt::init`, `rt::cleanup` and similar functions controlled by libstd. In those instances a
    // panic is a libstd implementation bug. A quite likely one too, as there isn't any way to
    // prevent libstd from accidentally introducing a panic to these functions. Another is from
    // user code from `main` or, more nefariously, as described in e.g. issue #86030.
    // SAFETY: Only called once during runtime initialization.
    panic::catch_unwind(move || unsafe { sys_common::rt::init(argc, argv) }).map_err(rt_abort)?;
    let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
        .map_err(move |e| {
            mem::forget(e);
            rtprintpanic!("drop of the panic payload panicked");
            sys::abort_internal()
        });
    panic::catch_unwind(sys_common::rt::cleanup).map_err(rt_abort)?;
    ret_code
}

#[cfg(not(test))]
#[lang = "start"]
fn lang_start<T: crate::process::Termination + 'static>(
    main: fn() -> T,
    argc: isize,
    argv: *const *const u8,
) -> isize {
    lang_start_internal(
        &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
        argc,
        argv,
    )
    .into_ok()
}
<commit_msg>Auto merge of #88988 - Mark-Simulacrum:avoid-into-ok, r=nagisa<commit_after>//! Runtime services
//!
//! The `rt` module provides a narrow set of runtime services,
//! including the global heap (exported in `heap`) and unwinding and
//! backtrace support. The APIs in this module are highly unstable,
//! and should be considered as private implementation details for the
//! time being.

#![unstable(
    feature = "rt",
    reason = "this public module should not exist and is highly likely \
              to disappear",
    issue = "none"
)]
#![doc(hidden)]

// Re-export some of our utilities which are expected by other crates.
pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
pub use core::panicking::panic_display;

// To reduce the generated code of the new `lang_start`, this function is doing
// the real work.
#[cfg(not(test))]
fn lang_start_internal(
    main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
    argc: isize,
    argv: *const *const u8,
) -> Result<isize, !> {
    use crate::{mem, panic, sys, sys_common};
    let rt_abort = move |e| {
        mem::forget(e);
        rtabort!("initialization or cleanup bug");
    };
    // Guard against the code called by this function from unwinding outside of the Rust-controlled
    // code, which is UB. This is a requirement imposed by a combination of how the
    // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
    // mechanism itself.
    //
    // There are a couple of instances where unwinding can begin. First is inside of the
    // `rt::init`, `rt::cleanup` and similar functions controlled by libstd. In those instances a
    // panic is a libstd implementation bug. A quite likely one too, as there isn't any way to
    // prevent libstd from accidentally introducing a panic to these functions. Another is from
    // user code from `main` or, more nefariously, as described in e.g. issue #86030.
    // SAFETY: Only called once during runtime initialization.
    panic::catch_unwind(move || unsafe { sys_common::rt::init(argc, argv) }).map_err(rt_abort)?;
    let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
        .map_err(move |e| {
            mem::forget(e);
            rtprintpanic!("drop of the panic payload panicked");
            sys::abort_internal()
        });
    panic::catch_unwind(sys_common::rt::cleanup).map_err(rt_abort)?;
    ret_code
}

#[cfg(not(test))]
#[lang = "start"]
fn lang_start<T: crate::process::Termination + 'static>(
    main: fn() -> T,
    argc: isize,
    argv: *const *const u8,
) -> isize {
    let Ok(v) = lang_start_internal(
        &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
        argc,
        argv,
    );
    v
}
<|endoftext|>