<commit_before>use entities::{ EntitiesState, EntitiesHelper, EntityID, ComponentID, NativeComponentType };
use std::collections::{ HashSet, HashMap };
use std::cell::RefCell;
use std::rc::Rc;
use nalgebra::na;
use nalgebra::na::{ Norm, Translation, Vec2, Vec3 };
use ncollide::geom::geom::Geom;
use nphysics::world::World;
use nphysics::object::{ RigidBody };
use log;

pub struct PhysicsSystem {
    world: World,
    bodies: HashMap<EntityID, Rc<RefCell<RigidBody>>>,
}

impl PhysicsSystem {
    pub fn new(_: &EntitiesState, log: |log::LogRecord|)
        -> PhysicsSystem
    {
        let mut world = World::new();
        world.set_gravity(Vec2::new(1.0f32, 1.0));

        let shape = ::ncollide::geom::Plane::new(Vec2::new(0.0f32, 1.0));
        let body = Rc::new(RefCell::new(RigidBody::new_static(shape, 0.3, 0.6)));
        //world.add_body(body);

        PhysicsSystem {
            world: world,
            bodies: HashMap::new()
        }
    }

    pub fn process(&mut self, state: &mut EntitiesState, elapsed: &f64, log: |log::LogRecord|)
    {
        // getting the list of all entities that have physics activated
        let listOfEntities: HashSet<EntityID> = state.get_components_iter()
            .filter(|c| state.is_component_visible(*c).unwrap())
            .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "physics", _ => false })
            .filter(|c| match state.get_as_boolean(*c, "activated") { Some(b) => b, _ => false })
            .map(|c| state.get_owner(c).unwrap())
            .collect();

        // removing from the world the elements that have disappeared
        {
            let toRemove: Vec<EntityID> = self.bodies.keys().filter(|e| !listOfEntities.contains(e.clone())).map(|e| e.clone()).collect();
            for e in toRemove.move_iter() {
                //self.bodies.find(&e).     // TODO: remove body from the world
                self.bodies.remove(&e);
            }
        }

        // adding elements that are not yet in the world
        {
            let toCreate: Vec<EntityID> = listOfEntities.iter().filter(|e| !self.bodies.contains_key(e.clone())).map(|e| e.clone()).collect();
            for e in toCreate.move_iter() {
                let shape = ::ncollide::geom::Cuboid::new(Vec2::new(0.5f32, 0.5f32));
                let body = Rc::new(RefCell::new(RigidBody::new_dynamic(shape, 1.0, 0.5, 0.0)));

                // initializing body with current position and movement
                body.borrow_mut().set_translation({ let p = get_entity_position(state, &e); na::Vec2::new(p.x,p.y) });
                body.borrow_mut().set_lin_vel({ let p = get_entity_movement(state, &e); na::Vec2::new(p.x,p.y) });
                body.borrow_mut().set_lin_acc_scale(na::Vec2::new(0.0, 0.0));

                self.bodies.insert(e.clone(), body.clone());
                self.world.add_body(body.clone());
            }
        }

        // setting all positions and movements
        for (entity, body) in self.bodies.iter() {
            let position = { let p = get_entity_position(state, entity); na::Vec2::new(p.x,p.y) };
            let movement = { let p = get_entity_movement(state, entity); na::Vec2::new(p.x,p.y) };
            let requestedMovement = get_requested_movement(state, entity);

            let mut borrowedBody = body.borrow_mut();
            borrowedBody.set_translation(position);
            borrowedBody.set_lin_vel(movement);

            if requestedMovement.is_some() && requestedMovement != Some(movement) {
                let acceleration = na::normalize(&(requestedMovement.unwrap() - movement));
                borrowedBody.set_lin_acc_scale(acceleration);
            }
        }

        // step
        self.world.step(*elapsed as f32);

        //
        for (entity, body) in self.bodies.iter() {
            set_position(state, entity, &body.borrow().translation());
            set_movement(state, entity, &body.borrow().lin_vel());
        }
    }
}

/// returns the position of an entity
pub fn get_entity_position(state: &EntitiesState, id: &EntityID)
    -> na::Vec3<f32>
{
    use std::iter::AdditiveIterator;

    state
        .get_visible_native_components("position")
        .move_iter()

        // take only the components owned by the entity
        .filter(|c| state.get_owner(c).unwrap() == *id)

        // build a vector from each of the component
        .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
            (Some(x), Some(y), Some(z))
                => Some(na::Vec3::new(x as f32, y as f32, z as f32)),
            (Some(x), Some(y), _)
                => Some(na::Vec3::new(x as f32, y as f32, 0.0)),
            _ => None
        })

        // add all the elements together
        .sum()
}

/// Returns the total movement of an entity.
pub fn get_entity_movement(state: &EntitiesState, id: &EntityID)
    -> na::Vec3<f32>
{
    use std::iter::AdditiveIterator;

    state
        .get_visible_native_components("movement")
        .move_iter()

        // take only the components owned by the entity
        .filter(|c| state.get_owner(c).unwrap() == *id)

        // build a vector from each of the component
        .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
            (Some(x), Some(y), Some(z))
                => Some(na::Vec3::new(x as f32, y as f32, z as f32)),
            (Some(x), Some(y), _)
                => Some(na::Vec3::new(x as f32, y as f32, 0.0)),
            _ => None
        })

        // add all the elements together
        .sum()
}

/// returns the total requested movement of an entity
pub fn get_requested_movement(state: &EntitiesState, id: &EntityID)
    -> Option<Vec2<f32>>
{
    state
        .get_visible_native_components("requestedMovement")
        .move_iter()

        // take only the components owned by the entity
        .filter(|c| state.get_owner(c).unwrap() == *id)

        // build a vector from each of the component
        .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
            (Some(x), Some(y), _)
                => Some(Vec2::new(x as f32, y as f32)),
            _ => None
        })

        // add all the elements together
        .fold(None, |vec: Option<Vec2<f32>>, a| match vec { None => Some(a), Some(v) => Some(v + a) })
}

/// changes the position of an entity
pub fn set_position(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
{
    let current = get_entity_position(state, id);
    let current = na::Vec2::new(current.x, current.y);
    adjust_position(state, id, &(pos - current));
}

/// updates the position of an entity
pub fn adjust_position(state: &mut EntitiesState, id: &EntityID, diff: &Vec2<f32>)
{
    let list: Vec<ComponentID> = state
        .get_components_iter()
        // take only the components owned by the entity
        .filter(|c| state.get_owner(*c).unwrap() == *id)
        // take only the "position" components
        .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })
        .filter(|c| state.get_as_boolean(*c, "autoupdate").unwrap_or(true))
        .map(|c| c.clone()).collect();

    if list.len() == 0 {
        let mut data = HashMap::new();
        data.insert("x".to_string(), ::entities::Number(diff.x as f64));
        data.insert("y".to_string(), ::entities::Number(diff.y as f64));
        state.create_native_component(id, "position", data);
        return
    }

    let diff = diff / (list.len() as f32);

    for cmp in list.iter() {
        let (x, y) = (
                state.get_as_number(cmp, "x").unwrap_or(0.0),
                state.get_as_number(cmp, "y").unwrap_or(0.0)
            );

        state.set(cmp, "x", ::entities::Number(x + diff.x as f64));
        state.set(cmp, "y", ::entities::Number(y + diff.y as f64));
    }
}

/// changes the position of an entity
pub fn set_movement(state: &mut EntitiesState, id: &EntityID, movement: &Vec2<f32>)
{
    let current = get_entity_movement(state, id);
    let current = na::Vec2::new(current.x, current.y);
    adjust_movement(state, id, &(movement - current));
}

/// changes the movement of an entity
pub fn adjust_movement(state: &mut EntitiesState, id: &EntityID, diff: &Vec2<f32>)
{
    let list: Vec<ComponentID> = state
        .get_visible_native_components("movement")
        .move_iter()
        // take only the components owned by the entity
        .filter(|c| state.get_owner(c).unwrap() == *id)
        .filter(|c| state.get_as_boolean(c, "autoupdate").unwrap_or(true))
        .collect();

    if list.len() == 0 {
        let mut data = HashMap::new();
        data.insert("x".to_string(), ::entities::Number(diff.x as f64));
        data.insert("y".to_string(), ::entities::Number(diff.y as f64));
        state.create_native_component(id, "movement", data);
        return
    }

    let diff = diff / (list.len() as f32);

    for cmp in list.iter() {
        let (x, y) = (
                state.get_as_number(cmp, "x").unwrap_or(0.0),
                state.get_as_number(cmp, "y").unwrap_or(0.0)
            );

        state.set(cmp, "x", ::entities::Number(x + diff.x as f64));
        state.set(cmp, "y", ::entities::Number(y + diff.y as f64));
    }
}
<commit_msg>Fix physics<commit_after>use entities::{ EntitiesState, EntitiesHelper, EntityID, ComponentID, NativeComponentType };
use std::collections::{ HashSet, HashMap };
use std::cell::RefCell;
use std::rc::Rc;
use nalgebra::na;
use nalgebra::na::{ Norm, Translation, Vec2, Vec3 };
use ncollide::geom::geom::Geom;
use nphysics::world::World;
use nphysics::object::{ RigidBody };
use log;

pub struct PhysicsSystem {
    world: World,
    bodies: HashMap<EntityID, Rc<RefCell<RigidBody>>>,
}

impl PhysicsSystem {
    pub fn new(_: &EntitiesState, log: |log::LogRecord|)
        -> PhysicsSystem
    {
        let mut world = World::new();
        world.set_gravity(Vec2::new(1.0f32, 1.0));

        //let shape = ::ncollide::geom::Plane::new(Vec2::new(0.0f32, 1.0));
        //let body = Rc::new(RefCell::new(RigidBody::new_static(shape, 0.3, 0.6)));
        //world.add_body(body);

        PhysicsSystem {
            world: world,
            bodies: HashMap::new()
        }
    }

    pub fn process(&mut self, state: &mut EntitiesState, elapsed: &f64, log: |log::LogRecord|)
    {
        // getting the list of all entities that have physics activated
        let listOfEntities: HashSet<EntityID> = state.get_components_iter()
            .filter(|c| state.is_component_visible(*c).unwrap())
            .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "physics", _ => false })
            .filter(|c| match state.get_as_boolean(*c, "activated") { Some(b) => b, _ => false })
            .map(|c| state.get_owner(c).unwrap())
            .collect();

        // removing from the world the elements that have disappeared
        {
            let toRemove: Vec<EntityID> = self.bodies.keys().filter(|e| !listOfEntities.contains(e.clone())).map(|e| e.clone()).collect();
            for e in toRemove.move_iter() {
                //self.bodies.find(&e).     // TODO: remove body from the world
                self.bodies.remove(&e);
            }
        }

        // adding elements that are not yet in the world
        {
            let toCreate: Vec<EntityID> = listOfEntities.iter().filter(|e| !self.bodies.contains_key(e.clone())).map(|e| e.clone()).collect();
            for e in toCreate.move_iter() {
                let shape = ::ncollide::geom::Cuboid::new(Vec2::new(0.5f32, 0.5f32));
                let body = Rc::new(RefCell::new(RigidBody::new_dynamic(shape, 1.0, 0.5, 0.0)));

                // initializing body with current position and movement
                body.borrow_mut().set_translation({ let p = get_entity_position(state, &e); na::Vec2::new(p.x,p.y) });
                body.borrow_mut().set_lin_vel({ let p = get_entity_movement(state, &e); na::Vec2::new(p.x,p.y) });
                body.borrow_mut().set_lin_acc_scale(na::Vec2::new(0.0, 0.0));

                self.bodies.insert(e.clone(), body.clone());
                self.world.add_body(body.clone());
            }
        }

        // setting all positions and movements
        for (entity, body) in self.bodies.iter() {
            let position = { let p = get_entity_position(state, entity); na::Vec2::new(p.x,p.y) };
            let movement = { let p = get_entity_movement(state, entity); na::Vec2::new(p.x,p.y) };
            let requestedMovement = get_requested_movement(state, entity);

            let mut borrowedBody = body.borrow_mut();
            borrowedBody.set_translation(position);
            borrowedBody.set_lin_vel(movement);
            borrowedBody.activate(100.0);       // objects tend to deactivate too often

            if requestedMovement.is_some() {
                let requestedMovement = requestedMovement.unwrap();

                let acceleration: Vec2<f32> = Vec2::new(
                    if requestedMovement.x < 0.0 && requestedMovement.x < movement.x { -1.0 }
                    else if requestedMovement.x > 0.0 && requestedMovement.x > movement.x { 1.0 }
                    else { 0.0 },
                    if requestedMovement.y < 0.0 && requestedMovement.y < movement.y { -1.0 }
                    else if requestedMovement.y > 0.0 && requestedMovement.y > movement.y { 1.0 }
                    else { 0.0 }
                );

                if acceleration != borrowedBody.lin_acc_scale() {
                    borrowedBody.set_lin_acc_scale(acceleration);
                }
            }
        }

        // step
        self.world.step(*elapsed as f32);

        //
        for (entity, body) in self.bodies.iter() {
            set_position(state, entity, &body.borrow().translation());
            set_movement(state, entity, &body.borrow().lin_vel());
        }
    }
}

/// returns the position of an entity
pub fn get_entity_position(state: &EntitiesState, id: &EntityID)
    -> na::Vec3<f32>
{
    use std::iter::AdditiveIterator;

    state
        .get_visible_native_components("position")
        .move_iter()

        // take only the components owned by the entity
        .filter(|c| state.get_owner(c).unwrap() == *id)

        // build a vector from each of the component
        .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
            (Some(x), Some(y), Some(z))
                => Some(na::Vec3::new(x as f32, y as f32, z as f32)),
            (Some(x), Some(y), _)
                => Some(na::Vec3::new(x as f32, y as f32, 0.0)),
            _ => None
        })

        // add all the elements together
        .sum()
}

/// Returns the total movement of an entity.
pub fn get_entity_movement(state: &EntitiesState, id: &EntityID)
    -> na::Vec3<f32>
{
    use std::iter::AdditiveIterator;

    state
        .get_visible_native_components("movement")
        .move_iter()

        // take only the components owned by the entity
        .filter(|c| state.get_owner(c).unwrap() == *id)

        // build a vector from each of the component
        .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
            (Some(x), Some(y), Some(z))
                => Some(na::Vec3::new(x as f32, y as f32, z as f32)),
            (Some(x), Some(y), _)
                => Some(na::Vec3::new(x as f32, y as f32, 0.0)),
            _ => None
        })

        // add all the elements together
        .sum()
}

/// returns the total requested movement of an entity
pub fn get_requested_movement(state: &EntitiesState, id: &EntityID)
    -> Option<Vec2<f32>>
{
    state
        .get_visible_native_components("requestedMovement")
        .move_iter()

        // take only the components owned by the entity
        .filter(|c| state.get_owner(c).unwrap() == *id)

        // build a vector from each of the component
        .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
            (Some(x), Some(y), _)
                => Some(Vec2::new(x as f32, y as f32)),
            _ => None
        })

        // add all the elements together
        .fold(None, |vec: Option<Vec2<f32>>, a| match vec { None => Some(a), Some(v) => Some(v + a) })
}

/// changes the position of an entity
pub fn set_position(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
{
    let current = get_entity_position(state, id);
    let current = na::Vec2::new(current.x, current.y);
    adjust_position(state, id, &(pos - current));
}

/// updates the position of an entity
pub fn adjust_position(state: &mut EntitiesState, id: &EntityID, diff: &Vec2<f32>)
{
    let list: Vec<ComponentID> = state
        .get_components_iter()
        // take only the components owned by the entity
        .filter(|c| state.get_owner(*c).unwrap() == *id)
        // take only the "position" components
        .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })
        .filter(|c| state.get_as_boolean(*c, "autoupdate").unwrap_or(true))
        .map(|c| c.clone()).collect();

    if list.len() == 0 {
        let mut data = HashMap::new();
        data.insert("x".to_string(), ::entities::Number(diff.x as f64));
        data.insert("y".to_string(), ::entities::Number(diff.y as f64));
        state.create_native_component(id, "position", data);
        return
    }

    let diff = diff / (list.len() as f32);

    for cmp in list.iter() {
        let (x, y) = (
                state.get_as_number(cmp, "x").unwrap_or(0.0),
                state.get_as_number(cmp, "y").unwrap_or(0.0)
            );

        state.set(cmp, "x", ::entities::Number(x + diff.x as f64));
        state.set(cmp, "y", ::entities::Number(y + diff.y as f64));
    }
}

/// changes the position of an entity
pub fn set_movement(state: &mut EntitiesState, id: &EntityID, movement: &Vec2<f32>)
{
    let current = get_entity_movement(state, id);
    let current = na::Vec2::new(current.x, current.y);
    adjust_movement(state, id, &(movement - current));
}

/// changes the movement of an entity
pub fn adjust_movement(state: &mut EntitiesState, id: &EntityID, diff: &Vec2<f32>)
{
    let list: Vec<ComponentID> = state
        .get_visible_native_components("movement")
        .move_iter()
        // take only the components owned by the entity
        .filter(|c| state.get_owner(c).unwrap() == *id)
        .filter(|c| state.get_as_boolean(c, "autoupdate").unwrap_or(true))
        .collect();

    if list.len() == 0 {
        let mut data = HashMap::new();
        data.insert("x".to_string(), ::entities::Number(diff.x as f64));
        data.insert("y".to_string(), ::entities::Number(diff.y as f64));
        state.create_native_component(id, "movement", data);
        return
    }

    let diff = diff / (list.len() as f32);

    for cmp in list.iter() {
        let (x, y) = (
                state.get_as_number(cmp, "x").unwrap_or(0.0),
                state.get_as_number(cmp, "y").unwrap_or(0.0)
            );

        state.set(cmp, "x", ::entities::Number(x + diff.x as f64));
        state.set(cmp, "y", ::entities::Number(y + diff.y as f64));
    }
}
<|endoftext|>


<commit_before>#![cfg(not(windows))]

extern crate libc;

use screen::Key;
use screen::Key::*;
use std::io::{Read, Write};
use std::fs::{File, OpenOptions};
use std::os::unix::io::AsRawFd;
use std::path::*;
use std::process::Command;
use std::process::Stdio;
use std::str;
use std::iter::repeat;
use std::cmp::min;
use ansi;
use ::NEWLINE;

use std::{mem, ptr};
use std::thread;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Arc, Mutex};

use self::libc::{sigaction, SIGWINCH, SA_SIGINFO, sighandler_t, c_int, c_ushort, c_ulong};

pub struct Screen {
    tty: Terminal,
    original_stty_state: Vec<u8>,
    start_line: u16,
    desired_rows: u16,
}

impl Screen {
    pub fn open_screen(desired_rows: u16) -> Screen {
        let mut tty = Terminal::open_terminal();
        let current_stty_state = tty.stty(&["-g"]);
        tty.initialize();
        let (_, rows) = tty.winsize().unwrap();
        let visible_choices = min(desired_rows, rows - 1);
        let start_line = rows - visible_choices - 1;
        for _ in 0..visible_choices {
            tty.write(NEWLINE.as_bytes());
        }
        tty.write(&ansi::save_cursor());

        Screen {
            tty: tty,
            original_stty_state: current_stty_state,
            start_line: start_line,
            desired_rows: desired_rows,
        }
    }

    pub fn visible_choices(&self) -> u16 {
        let (_, rows) = self.tty.winsize().unwrap();
        min(self.desired_rows, rows - 1)
    }

    pub fn width(&self) -> u16 {
        let (cols, _) = self.tty.winsize().unwrap();
        cols
    }

    fn restore_tty(&mut self) {
        self.tty.stty(&[&String::from_utf8(self.original_stty_state.clone()).unwrap()]);
    }

    fn reset_cursor(&mut self) {
        self.tty.write(&ansi::restore_cursor());

        // Writing this carriage return works around a rendering bug in
        // Neovim's terminal emulation. Without it, the cursor flies
        // around all over the place while typing, and the input prompt
        // is not rendered correctly. I have no idea why this workaround
        // is effective, or why others are not, or what the root cause
        // of the issue is (likely something involving save/restore
        // support).
        self.tty.write(b"\r");

        let num_lines = self.visible_choices();
        self.tty.write(&ansi::cursor_up(num_lines));
    }

    pub fn move_cursor_to_prompt_line(&mut self, col: u16) {
        self.reset_cursor();
        self.tty.write(&ansi::cursor_right(col));
    }

    pub fn blank_screen(&mut self) {
        self.reset_cursor();
        let blank_line = repeat(' ').take(self.width() as usize).collect::<String>();
        for _ in 0..self.visible_choices() + 1 {
            self.tty.write(blank_line.as_bytes());
        }
        self.reset_cursor();
    }

    pub fn blank_entire_screen(&mut self){
        self.tty.write(&ansi::blank_screen());
    }

    pub fn show_cursor(&mut self) {
        self.tty.write(&ansi::show_cursor());
    }

    pub fn hide_cursor(&mut self) {
        self.tty.write(&ansi::hide_cursor());
    }

    pub fn write(&mut self, s: &str) {
        self.tty.write(s.as_bytes());
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_red(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(bytes) = self.tty.input.try_recv() {
            ret.extend(bytes);
        }
        while ret.is_empty() {
            let bytes = self.tty.input.recv().unwrap();
            if bytes == vec![0] { // SIGWINCH
                self.blank_entire_screen();
                return vec![Nothing];
            } else {
                ret.extend(bytes);
            }
        }
        Terminal::translate_bytes(ret.clone())
    }

    fn more_bytes_needed(bytes: &[u8]) -> bool {
        if let Err(_) = str::from_utf8(bytes) { true } else { false }
    }
}

impl Drop for Screen {
    fn drop(&mut self) {
        self.restore_tty();
    }
}

struct Terminal {
    input: Receiver<Vec<u8>>,
    input_fd: i32,
    output: File,
}

static mut GLOBAL_TX: *const Arc<Mutex<Sender<Vec<u8>>>> = 0 as *const Arc<Mutex<Sender<Vec<u8>>>>;

fn set_global_tx(tx: Sender<Vec<u8>>) {
    unsafe {
        let singleton = Arc::new(Mutex::new(tx));
        GLOBAL_TX = mem::transmute(Box::new(singleton));
    }
}

fn get_global_tx() -> Sender<Vec<u8>> {
    let singleton = unsafe { (*GLOBAL_TX).clone() };
    let tx = singleton.lock().unwrap();
    tx.clone()
}

unsafe extern fn sigwinch_handler(signum: c_int) {
    if signum == SIGWINCH {
        get_global_tx().send([0].to_vec()).unwrap();
    }
}

fn register_sigwinch_handler() {
    unsafe {
        let mut action: sigaction = mem::zeroed();
        action.sa_flags = SA_SIGINFO;
        action.sa_sigaction = sigwinch_handler as sighandler_t;
        sigaction(SIGWINCH, &action, ptr::null_mut());
    }
}

impl Terminal {
    fn open_terminal() -> Terminal {
        let term_path = Path::new("/dev/tty");
        let mut input_file = File::open(&term_path).unwrap();
        let output_file = OpenOptions::new().write(true).open(&term_path).unwrap();
        let input_fd = input_file.as_raw_fd();
        let (tx, rx) = mpsc::channel();
        set_global_tx(tx);

        register_sigwinch_handler();

        thread::spawn(move || {
            loop {
                let mut buf = [0; 255];
                let tx = get_global_tx();
                if let Ok(length) = input_file.read(&mut buf) {
                    tx.send(buf[0..length].to_vec()).unwrap();
                } else {
                    tx.send([0].to_vec()).unwrap();
                }
            }
        });
        Terminal {
            input: rx,
            input_fd: input_fd,
            output: output_file,
        }
    }

    fn initialize(&mut self) {
        self.stty(&["raw", "-echo", "cbreak", "opost", "onlcr"]);
    }

    fn stty(&mut self, args: &[&str]) -> Vec<u8> {
        extern { fn dup2(src: c_int, dst: c_int) -> c_int;  }
        unsafe {
            // This is a hack until a replacement for InheritFd from old_io is available.
            dup2(self.input_fd, 0);
        }
        let mut process = match Command::new("stty")
            .args(args)
            .stdin(Stdio::inherit())
            .stdout(Stdio::piped())
            .spawn()
        {
            Ok(p) => p,
            Err(e) => panic!("Spawn failed: {}", e),
        };

        let exit = process.wait();

        let mut buf = Vec::new();
        if exit.unwrap().success() {
            process.stdout.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            let mut str = String::from_utf8(buf).unwrap();

            // The output from `stty -g` may include a newline, which we have to strip off. Otherwise,
            // when we go to restore the tty, stty (on some platforms) will fail with an "invalid
            // argument" error.
            ::trim(&mut str);

            str.into_bytes()
        } else {
            process.stderr.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            panic!(String::from_utf8(buf).unwrap());
        }
    }

    fn translate_bytes(bytes: Vec<u8>) -> Vec<Key> {
        const BEGIN_PASTE: &'static [u8] = b"\x1B[200~";
        const END_PASTE: &'static [u8] = b"\x1B[201~";

        if bytes == b"\x1B[A" || bytes == b"\x1BOA" { return vec![Up] };
        if bytes == b"\x1B[B" || bytes == b"\x1BOB" { return vec![Down] };
        if bytes == b"\x1B[Z" { return vec![ShiftTab] };

        let bs = if bytes.starts_with(BEGIN_PASTE) && bytes.ends_with(END_PASTE) {
            let start = BEGIN_PASTE.len();
            let end = bytes.len() - END_PASTE.len();
            bytes[start..end].to_vec()
        } else {
            bytes
        };

        String::from_utf8(bs)
            .unwrap()
            .chars()
            .map(Terminal::translate_char)
            .collect()
    }

    fn translate_char(c: char) -> Key {
        let numeric_char = c as u32;
        if c == '\r' {
            Enter
        } else if numeric_char == 9 {
            Tab
        } else if numeric_char == 127 {
            Backspace
        } else if numeric_char & 96 == 0 && numeric_char <= 128u32 {
            let c = c as u8;
            Control((c + 96u8) as char)
        } else {
            Char(c)
        }
    }

    fn write(&mut self, s: &[u8]) {
        self.output.write_all(s).unwrap();
    }

    fn writeln(&mut self, s: &str) {
        self.output.write(s.as_bytes()).unwrap();
        self.output.write(b"\n").unwrap();
    }

    fn winsize(&self) -> Option<(u16, u16)> {
        extern { fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; }
        #[cfg(any(target_os = "macos", target_os = "freebsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(self.output.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            Some((size.cols as u16, size.rows as u16))
        } else {
            None
        }
    }
}

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

    #[test]
    fn winsize_test() {
        // Travis-CI builds run without a tty, making this test impossible.
        if option_env!("TRAVIS").is_some() {
            // TODO: It should be made obvious from the output that this test was skipped
            return;
        }
        let term = Terminal::open_terminal();
        let (cols, rows) = term.winsize().expect("Failed to get window size!");
        // We don't know the window size a priori, but we can at least
        // assert that it is within some kind of sensible range.
        assert!(cols > 40);
        assert!(rows > 40);
        assert!(cols < 1000);
        assert!(rows < 1000);
    }
}
<commit_msg>Define TIOCGWINSZ on netbsd<commit_after>#![cfg(not(windows))]

extern crate libc;

use screen::Key;
use screen::Key::*;
use std::io::{Read, Write};
use std::fs::{File, OpenOptions};
use std::os::unix::io::AsRawFd;
use std::path::*;
use std::process::Command;
use std::process::Stdio;
use std::str;
use std::iter::repeat;
use std::cmp::min;
use ansi;
use ::NEWLINE;

use std::{mem, ptr};
use std::thread;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Arc, Mutex};

use self::libc::{sigaction, SIGWINCH, SA_SIGINFO, sighandler_t, c_int, c_ushort, c_ulong};

pub struct Screen {
    tty: Terminal,
    original_stty_state: Vec<u8>,
    start_line: u16,
    desired_rows: u16,
}

impl Screen {
    pub fn open_screen(desired_rows: u16) -> Screen {
        let mut tty = Terminal::open_terminal();
        let current_stty_state = tty.stty(&["-g"]);
        tty.initialize();
        let (_, rows) = tty.winsize().unwrap();
        let visible_choices = min(desired_rows, rows - 1);
        let start_line = rows - visible_choices - 1;
        for _ in 0..visible_choices {
            tty.write(NEWLINE.as_bytes());
        }
        tty.write(&ansi::save_cursor());

        Screen {
            tty: tty,
            original_stty_state: current_stty_state,
            start_line: start_line,
            desired_rows: desired_rows,
        }
    }

    pub fn visible_choices(&self) -> u16 {
        let (_, rows) = self.tty.winsize().unwrap();
        min(self.desired_rows, rows - 1)
    }

    pub fn width(&self) -> u16 {
        let (cols, _) = self.tty.winsize().unwrap();
        cols
    }

    fn restore_tty(&mut self) {
        self.tty.stty(&[&String::from_utf8(self.original_stty_state.clone()).unwrap()]);
    }

    fn reset_cursor(&mut self) {
        self.tty.write(&ansi::restore_cursor());

        // Writing this carriage return works around a rendering bug in
        // Neovim's terminal emulation. Without it, the cursor flies
        // around all over the place while typing, and the input prompt
        // is not rendered correctly. I have no idea why this workaround
        // is effective, or why others are not, or what the root cause
        // of the issue is (likely something involving save/restore
        // support).
        self.tty.write(b"\r");

        let num_lines = self.visible_choices();
        self.tty.write(&ansi::cursor_up(num_lines));
    }

    pub fn move_cursor_to_prompt_line(&mut self, col: u16) {
        self.reset_cursor();
        self.tty.write(&ansi::cursor_right(col));
    }

    pub fn blank_screen(&mut self) {
        self.reset_cursor();
        let blank_line = repeat(' ').take(self.width() as usize).collect::<String>();
        for _ in 0..self.visible_choices() + 1 {
            self.tty.write(blank_line.as_bytes());
        }
        self.reset_cursor();
    }

    pub fn blank_entire_screen(&mut self){
        self.tty.write(&ansi::blank_screen());
    }

    pub fn show_cursor(&mut self) {
        self.tty.write(&ansi::show_cursor());
    }

    pub fn hide_cursor(&mut self) {
        self.tty.write(&ansi::hide_cursor());
    }

    pub fn write(&mut self, s: &str) {
        self.tty.write(s.as_bytes());
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_red(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(bytes) = self.tty.input.try_recv() {
            ret.extend(bytes);
        }
        while ret.is_empty() {
            let bytes = self.tty.input.recv().unwrap();
            if bytes == vec![0] { // SIGWINCH
                self.blank_entire_screen();
                return vec![Nothing];
            } else {
                ret.extend(bytes);
            }
        }
        Terminal::translate_bytes(ret.clone())
    }

    fn more_bytes_needed(bytes: &[u8]) -> bool {
        if let Err(_) = str::from_utf8(bytes) { true } else { false }
    }
}

impl Drop for Screen {
    fn drop(&mut self) {
        self.restore_tty();
    }
}

struct Terminal {
    input: Receiver<Vec<u8>>,
    input_fd: i32,
    output: File,
}

static mut GLOBAL_TX: *const Arc<Mutex<Sender<Vec<u8>>>> = 0 as *const Arc<Mutex<Sender<Vec<u8>>>>;

fn set_global_tx(tx: Sender<Vec<u8>>) {
    unsafe {
        let singleton = Arc::new(Mutex::new(tx));
        GLOBAL_TX = mem::transmute(Box::new(singleton));
    }
}

fn get_global_tx() -> Sender<Vec<u8>> {
    let singleton = unsafe { (*GLOBAL_TX).clone() };
    let tx = singleton.lock().unwrap();
    tx.clone()
}

unsafe extern fn sigwinch_handler(signum: c_int) {
    if signum == SIGWINCH {
        get_global_tx().send([0].to_vec()).unwrap();
    }
}

fn register_sigwinch_handler() {
    unsafe {
        let mut action: sigaction = mem::zeroed();
        action.sa_flags = SA_SIGINFO;
        action.sa_sigaction = sigwinch_handler as sighandler_t;
        sigaction(SIGWINCH, &action, ptr::null_mut());
    }
}

impl Terminal {
    fn open_terminal() -> Terminal {
        let term_path = Path::new("/dev/tty");
        let mut input_file = File::open(&term_path).unwrap();
        let output_file = OpenOptions::new().write(true).open(&term_path).unwrap();
        let input_fd = input_file.as_raw_fd();
        let (tx, rx) = mpsc::channel();
        set_global_tx(tx);

        register_sigwinch_handler();

        thread::spawn(move || {
            loop {
                let mut buf = [0; 255];
                let tx = get_global_tx();
                if let Ok(length) = input_file.read(&mut buf) {
                    tx.send(buf[0..length].to_vec()).unwrap();
                } else {
                    tx.send([0].to_vec()).unwrap();
                }
            }
        });
        Terminal {
            input: rx,
            input_fd: input_fd,
            output: output_file,
        }
    }

    fn initialize(&mut self) {
        self.stty(&["raw", "-echo", "cbreak", "opost", "onlcr"]);
    }

    fn stty(&mut self, args: &[&str]) -> Vec<u8> {
        extern { fn dup2(src: c_int, dst: c_int) -> c_int;  }
        unsafe {
            // This is a hack until a replacement for InheritFd from old_io is available.
            dup2(self.input_fd, 0);
        }
        let mut process = match Command::new("stty")
            .args(args)
            .stdin(Stdio::inherit())
            .stdout(Stdio::piped())
            .spawn()
        {
            Ok(p) => p,
            Err(e) => panic!("Spawn failed: {}", e),
        };

        let exit = process.wait();

        let mut buf = Vec::new();
        if exit.unwrap().success() {
            process.stdout.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            let mut str = String::from_utf8(buf).unwrap();

            // The output from `stty -g` may include a newline, which we have to strip off. Otherwise,
            // when we go to restore the tty, stty (on some platforms) will fail with an "invalid
            // argument" error.
            ::trim(&mut str);

            str.into_bytes()
        } else {
            process.stderr.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            panic!(String::from_utf8(buf).unwrap());
        }
    }

    fn translate_bytes(bytes: Vec<u8>) -> Vec<Key> {
        const BEGIN_PASTE: &'static [u8] = b"\x1B[200~";
        const END_PASTE: &'static [u8] = b"\x1B[201~";

        if bytes == b"\x1B[A" || bytes == b"\x1BOA" { return vec![Up] };
        if bytes == b"\x1B[B" || bytes == b"\x1BOB" { return vec![Down] };
        if bytes == b"\x1B[Z" { return vec![ShiftTab] };

        let bs = if bytes.starts_with(BEGIN_PASTE) && bytes.ends_with(END_PASTE) {
            let start = BEGIN_PASTE.len();
            let end = bytes.len() - END_PASTE.len();
            bytes[start..end].to_vec()
        } else {
            bytes
        };

        String::from_utf8(bs)
            .unwrap()
            .chars()
            .map(Terminal::translate_char)
            .collect()
    }

    fn translate_char(c: char) -> Key {
        let numeric_char = c as u32;
        if c == '\r' {
            Enter
        } else if numeric_char == 9 {
            Tab
        } else if numeric_char == 127 {
            Backspace
        } else if numeric_char & 96 == 0 && numeric_char <= 128u32 {
            let c = c as u8;
            Control((c + 96u8) as char)
        } else {
            Char(c)
        }
    }

    fn write(&mut self, s: &[u8]) {
        self.output.write_all(s).unwrap();
    }

    fn writeln(&mut self, s: &str) {
        self.output.write(s.as_bytes()).unwrap();
        self.output.write(b"\n").unwrap();
    }

    fn winsize(&self) -> Option<(u16, u16)> {
        extern { fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; }
        #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(self.output.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            Some((size.cols as u16, size.rows as u16))
        } else {
            None
        }
    }
}

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

    #[test]
    fn winsize_test() {
        // Travis-CI builds run without a tty, making this test impossible.
        if option_env!("TRAVIS").is_some() {
            // TODO: It should be made obvious from the output that this test was skipped
            return;
        }
        let term = Terminal::open_terminal();
        let (cols, rows) = term.winsize().expect("Failed to get window size!");
        // We don't know the window size a priori, but we can at least
        // assert that it is within some kind of sensible range.
        assert!(cols > 40);
        assert!(rows > 40);
        assert!(cols < 1000);
        assert!(rows < 1000);
    }
}
<|endoftext|>


<commit_before>mod error;

use fleetspeak::Packet;

use crate::action::Response;
pub use self::error::Error;

pub type Result<T> = std::result::Result<T, Error>;

pub trait Session {
    fn send<R: Response>(&mut self, response: R) -> Result<()>;
}

pub struct Action {
    id: String,
    request_id: u64,
    next_response_id: u64,
}

impl Action {

    pub fn new(session_id: String, request_id: u64) -> Action {
        Action {
            id: session_id,
            request_id: request_id,
            next_response_id: 0,
        }
    }
}

impl Session for Action {

    fn send<R: Response>(&mut self, response: R) -> Result<()> {
        Message {
            session_id: self.id.clone(),
            request_id: Some(self.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

pub struct Sink {
    id: &'static str,
}

impl Session for Sink {

    fn send<R: Response>(&mut self, response: R) -> Result<()> {
        Message {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }.send()
    }
}

pub fn startup() -> Sink {
    Sink { id: "/flows/F:Startup" }
}

struct Message<R: Response> {
    session_id: String,
    request_id: Option<u64>,
    response_id: Option<u64>,
    data: R,
}

impl<R: Response> Message<R> {

    fn send(self) -> Result<()> {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        let proto = rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: self.response_id,
            request_id: self.request_id,
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        };

        fleetspeak::send(Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: proto,
        })?;

        Ok(())
    }
}
<commit_msg>Rename session message to session response.<commit_after>mod error;

use fleetspeak::Packet;

use crate::action;
pub use self::error::Error;

pub type Result<T> = std::result::Result<T, Error>;

pub trait Session {
    fn send<R: action::Response>(&mut self, response: R) -> Result<()>;
}

pub struct Action {
    id: String,
    request_id: u64,
    next_response_id: u64,
}

impl Action {

    pub fn new(session_id: String, request_id: u64) -> Action {
        Action {
            id: session_id,
            request_id: request_id,
            next_response_id: 0,
        }
    }
}

impl Session for Action {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: self.id.clone(),
            request_id: Some(self.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

pub struct Sink {
    id: &'static str,
}

impl Session for Sink {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }.send()
    }
}

pub fn startup() -> Sink {
    Sink { id: "/flows/F:Startup" }
}

struct Response<R: action::Response> {
    session_id: String,
    request_id: Option<u64>,
    response_id: Option<u64>,
    data: R,
}

impl<R: action::Response> Response<R> {

    fn send(self) -> Result<()> {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        let proto = rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: self.response_id,
            request_id: self.request_id,
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        };

        fleetspeak::send(Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: proto,
        })?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2016 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.

// compile-flags: -Z emit-end-regions -Z borrowck-mir

fn guard() -> bool {
    false
}

fn guard2(_:i32) -> bool {
    true
}

fn full_tested_match()
{
    let _ = match Some(42) {
        Some(x) if guard() => 1 + x,
        Some(y) => 2 + y,
        None => 3
    };
}

fn main() {
    let _ = match Some(1) {
        Some(_w) if guard() => 1,
        _x => 2,
        Some(y) if guard2(y) => 3,
        _z => 4,
    };
}

// END RUST SOURCE
//
// START rustc.node17.NLL.before.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _5 = discriminant(_2);
//      switchInt(_5) -> [0isize: bb5, otherwise: bb3];
//  }
//  bb1: { // arm1
//      StorageLive(_7);
//      _7 = _3;
//      _1 = Add(const 1i32, _7);
//      ...
//      goto -> bb11;
//  }
//  bb2: { // binding3(empty) and arm3
//      _1 = const 3i32;
//      goto -> bb11;
//  }
//  bb3: {
//      falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1
//  }
//  bb4: {
//      falseEdges -> [real: bb10, imaginary: bb5]; //pre_binding2
//  }
//  bb5: {
//      falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3
//  }
//  bb6: {
//      unreachable;
//  }
//  bb7: { // binding1 and guard
//      StorageLive(_3);
//      _3 = ((_2 as Some).0: i32);
//      StorageLive(_6);
//      _6 = const guard() -> bb8;
//  }
//  bb8: { // end of guard
//      switchInt(_6) -> [0u8: bb9, otherwise: bb1];
//  }
//  bb9: { // to pre_binding2
//      falseEdges -> [real: bb4, imaginary: bb4];
//  }
//  bb10: { // binding2 and arm2
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      StorageLive(_8);
//      _8 = _4;
//      _1 = Add(const 2i32, _8);
//      StorageDead(_8);
//      goto -> bb11;
//  }
//  bb11: {
//      ...
//      return;
//  }
//
//
// END rustc.node17.NLL.before.mir
//
// START rustc.node40.NLL.before.mir
// bb0: {
//     ...
//     _2 = std::option::Option<i32>::Some(const 1i32,);
//     _7 = discriminant(_2);
//     switchInt(_7) -> [1isize: bb3, otherwise: bb4];
// }
// bb1: { // arm1
//      _1 = const 1i32;
//      goto -> bb16;
// }
// bb2: { // arm3
//     _1 = const 3i32;
//      goto -> bb16;
// }
//
//  bb3: {
//      falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
//  }
//  bb4: {
//      falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2
//  }
//  bb5: {
//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3
//  }
//  bb6: {
//      falseEdges -> [real: bb15, imaginary: bb7]; //pre_binding4
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: { // binding1: Some(w) if guard()
//      StorageLive(_3);
//      _3 = ((_2 as Some).0: i32);
//      StorageLive(_8);
//      _8 = const guard() -> bb9;
//  }
//  bb9: { //end of guard
//      switchInt(_8) -> [0u8: bb10, otherwise: bb1];
//  }
//  bb10: { // to pre_binding2
//      falseEdges -> [real: bb4, imaginary: bb4];
//  }
//  bb11: { // binding2 & arm2
//      StorageLive(_4);
//      _4 = _2;
//      _1 = const 2i32;
//      goto -> bb16;
//  }
//  bb12: { // binding3: Some(y) if guard2(y)
//      StorageLive(_5);
//      _5 = ((_2 as Some).0: i32);
//      StorageLive(_10);
//      StorageLive(_11);
//      _11 = _5;
//      _10 = const guard2(_11) -> bb13;
//  }
//  bb13: { // end of guard2
//      StorageDead(_11);
//      switchInt(_10) -> [0u8: bb14, otherwise: bb2];
//  }
//  bb14: { // to pre_binding4
//      falseEdges -> [real: bb6, imaginary: bb6];
//  }
//  bb15: { // binding4 & arm4
//      StorageLive(_6);
//      _6 = _2;
//      _1 = const 4i32;
//      goto -> bb16;
//  }
// bb16: {
//     ...
//     return;
// }
// END rustc.node40.NLL.before.mir
<commit_msg>add one more sample<commit_after>// Copyright 2012-2016 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.

// compile-flags: -Z emit-end-regions -Z borrowck-mir

fn guard() -> bool {
    false
}

fn guard2(_:i32) -> bool {
    true
}

fn full_tested_match() {
    let _ = match Some(42) {
        Some(x) if guard() => 1 + x,
        Some(y) => 2 + y,
        None => 3,
    };
}

fn full_tested_match2() {
    let _ = match Some(42) {
        Some(x) if guard() => 1 + x,
        None => 3,
        Some(y) => 2 + y,
    };
}

fn main() {
    let _ = match Some(1) {
        Some(_w) if guard() => 1,
        _x => 2,
        Some(y) if guard2(y) => 3,
        _z => 4,
    };
}

// END RUST SOURCE
//
// START rustc.node17.NLL.before.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _5 = discriminant(_2);
//      switchInt(_5) -> [0isize: bb5, otherwise: bb3];
//  }
//  bb1: { // arm1
//      StorageLive(_7);
//      _7 = _3;
//      _1 = Add(const 1i32, _7);
//      ...
//      goto -> bb11;
//  }
//  bb2: { // binding3(empty) and arm3
//      _1 = const 3i32;
//      goto -> bb11;
//  }
//  bb3: {
//      falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1
//  }
//  bb4: {
//      falseEdges -> [real: bb10, imaginary: bb5]; //pre_binding2
//  }
//  bb5: {
//      falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3
//  }
//  bb6: {
//      unreachable;
//  }
//  bb7: { // binding1 and guard
//      StorageLive(_3);
//      _3 = ((_2 as Some).0: i32);
//      StorageLive(_6);
//      _6 = const guard() -> bb8;
//  }
//  bb8: { // end of guard
//      switchInt(_6) -> [0u8: bb9, otherwise: bb1];
//  }
//  bb9: { // to pre_binding2
//      falseEdges -> [real: bb4, imaginary: bb4];
//  }
//  bb10: { // binding2 and arm2
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      StorageLive(_8);
//      _8 = _4;
//      _1 = Add(const 2i32, _8);
//      StorageDead(_8);
//      goto -> bb11;
//  }
//  bb11: {
//      ...
//      return;
//  }
// END rustc.node17.NLL.before.mir
//
// START rustc.node40.NLL.before.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _5 = discriminant(_2);
//      switchInt(_5) -> [0isize: bb4, otherwise: bb3];
//  }
//  bb1: { // arm1
//      StorageLive(_7);
//      _7 = _3;
//      _1 = Add(const 1i32, _7);
//      ...
//      goto -> bb11;
//  }
//  bb2: { // binding3(empty) and arm3
//      _1 = const 3i32;
//      goto -> bb11;
//  }
//  bb3: {
//      falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1
//  }
//  bb4: {
//      falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2
//  }
//  bb5: {
//      falseEdges -> [real: bb10, imaginary: bb6]; //pre_binding3
//  }
//  bb6: {
//      unreachable;
//  }
//  bb7: { // binding1 and guard
//      StorageLive(_3);
//      _3 = ((_2 as Some).0: i32);
//      StorageLive(_6);
//      _6 = const guard() -> bb8;
//  }
//  bb8: { // end of guard
//      switchInt(_6) -> [0u8: bb9, otherwise: bb1];
//  }
//  bb9: { // to pre_binding2
//      falseEdges -> [real: bb5, imaginary: bb4];
//  }
//  bb10: { // binding2 and arm2
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      StorageLive(_8);
//      _8 = _4;
//      _1 = Add(const 2i32, _8);
//      StorageDead(_8);
//      goto -> bb11;
//  }
//  bb11: {
//      ...
//      return;
//  }
// END rustc.node40.NLL.before.mir
//
// START rustc.node63.NLL.before.mir
// bb0: {
//     ...
//     _2 = std::option::Option<i32>::Some(const 1i32,);
//     _7 = discriminant(_2);
//     switchInt(_7) -> [1isize: bb3, otherwise: bb4];
// }
// bb1: { // arm1
//      _1 = const 1i32;
//      goto -> bb16;
// }
// bb2: { // arm3
//     _1 = const 3i32;
//      goto -> bb16;
// }
//
//  bb3: {
//      falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
//  }
//  bb4: {
//      falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2
//  }
//  bb5: {
//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3
//  }
//  bb6: {
//      falseEdges -> [real: bb15, imaginary: bb7]; //pre_binding4
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: { // binding1: Some(w) if guard()
//      StorageLive(_3);
//      _3 = ((_2 as Some).0: i32);
//      StorageLive(_8);
//      _8 = const guard() -> bb9;
//  }
//  bb9: { //end of guard
//      switchInt(_8) -> [0u8: bb10, otherwise: bb1];
//  }
//  bb10: { // to pre_binding2
//      falseEdges -> [real: bb4, imaginary: bb4];
//  }
//  bb11: { // binding2 & arm2
//      StorageLive(_4);
//      _4 = _2;
//      _1 = const 2i32;
//      goto -> bb16;
//  }
//  bb12: { // binding3: Some(y) if guard2(y)
//      StorageLive(_5);
//      _5 = ((_2 as Some).0: i32);
//      StorageLive(_10);
//      StorageLive(_11);
//      _11 = _5;
//      _10 = const guard2(_11) -> bb13;
//  }
//  bb13: { // end of guard2
//      StorageDead(_11);
//      switchInt(_10) -> [0u8: bb14, otherwise: bb2];
//  }
//  bb14: { // to pre_binding4
//      falseEdges -> [real: bb6, imaginary: bb6];
//  }
//  bb15: { // binding4 & arm4
//      StorageLive(_6);
//      _6 = _2;
//      _1 = const 4i32;
//      goto -> bb16;
//  }
// bb16: {
//     ...
//     return;
// }
// END rustc.node63.NLL.before.mir
<|endoftext|>


<commit_before>//! The module implements the framing layer of HTTP/2 and exposes an API for using it.
use std::u32;

use self::frame::settings::HttpSettings;

pub mod frame;
pub mod connection;
pub mod session;
pub mod header;

// 6.5.2 Defined SETTINGS Parameters
pub const DEFAULT_SETTINGS: HttpSettings = HttpSettings {
    header_table_size: 4_096,
    enable_push: true,
    max_concurrent_streams: u32::MAX,
    initial_window_size: 65_535,
    max_frame_size: 16_384,
    max_header_list_size: u32::MAX,
};

/// An alias for the type that represents the ID of an HTTP/2 stream
pub type StreamId = u32;

/// A set of protocol names that the library should use to indicate that HTTP/2
/// is supported during protocol negotiation (NPN or ALPN).
/// We include some of the drafts' protocol names, since there is basically no
/// difference for all intents and purposes (and some servers out there still
/// only officially advertise draft support).
/// TODO: Eventually only use "h2".
pub const ALPN_PROTOCOLS: &'static [&'static [u8]] = &[b"h2", b"h2-16", b"h2-15", b"h2-14"];

/// A sender MUST NOT allow a flow-control window to exceed 231-1 octets. If a sender receives
/// a WINDOW_UPDATE that causes a flow-control window to exceed this maximum,
/// it MUST terminate either the stream or the connection, as appropriate. For streams,
/// the sender sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR; for the connection,
/// a GOAWAY frame with an error code of FLOW_CONTROL_ERROR is sent.
pub const MAX_WINDOW_SIZE: u32 = 0x7fffffff;

// 6.9 WINDOW_UPDATE
/// The payload of a WINDOW_UPDATE frame is one reserved bit plus an unsigned 31-bit integer
/// indicating the number of octets that the sender can transmit in addition to the existing
/// flow-control window. The legal range for the increment to the flow-control window
/// is 1 to 231-1 (2,147,483,647) octets.
pub const MAX_WINDOW_SIZE_INC: u32 = 0x7fffffff;

/// The struct represents the size of a flow control window.
///
/// It exposes methods that allow the manipulation of window sizes, such that they can never
/// overflow the spec-mandated upper bound.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct WindowSize(pub i32);
impl WindowSize {
    /// Tries to increase the window size by the given delta. If the WindowSize would overflow the
    /// maximum allowed value (2^31 - 1), returns an error case. If the increase succeeds, returns
    /// `Ok`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use httpbis::solicit::WindowSize;
    ///
    /// let mut window_size = WindowSize::new(65_535);
    /// assert_eq!(window_size.size(), 65_535);
    /// // An increase within the bounds...
    /// assert!(window_size.try_increase(100).is_ok());
    /// assert_eq!(window_size.size(), 65_635);
    /// // An increase that would overflow
    /// assert!(window_size.try_increase(0x7fffffff).is_err());
    /// assert_eq!(window_size.size(), 65_635);
    /// ```
    pub fn try_increase(&mut self, delta: u32) -> Result<(), ()> {
        // Someone's provided a delta that would definitely overflow the window size.
        if delta > MAX_WINDOW_SIZE_INC || delta == 0 {
            return Err(());
        }
        // Now it is safe to cast the delta to the `i32`.
        match self.0.checked_add(delta as i32) {
            None => {
                // When the add overflows, we will have went over the maximum allowed size of the
                // window size...
                Err(())
            }
            Some(next_val) => {
                // The addition didn't overflow, so the next window size is in the range allowed by
                // the spec.
                self.0 = next_val;
                Ok(())
            }
        }
    }

    /// Tries to decrease the size of the window by the given delta.
    ///
    /// There are situations where the window size should legitimately be allowed to become
    /// negative, so the only situation where the result is an error is if the window size would
    /// underflow, as this would definitely cause the peers to lose sync.
    ///
    /// # Example
    ///
    /// ```rust
    /// use httpbis::solicit::WindowSize;
    ///
    /// let mut window_size = WindowSize::new(65_535);
    /// assert_eq!(window_size.size(), 65_535);
    /// // A decrease...
    /// assert!(window_size.try_decrease(100).is_ok());
    /// assert_eq!(window_size.size(), 65_435);
    /// // A decrease that does not underflow
    /// assert!(window_size.try_decrease(0x7fffffff).is_ok());
    /// assert_eq!(window_size.size(), -2147418212);
    /// // A decrease that *would* underflow
    /// assert!(window_size.try_decrease(0x7fffffff).is_err());
    /// assert_eq!(window_size.size(), -2147418212);
    /// ```
    pub fn try_decrease(&mut self, delta: i32) -> Result<(), ()> {
        match self.0.checked_sub(delta) {
            Some(new) => {
                self.0 = new;
                Ok(())
            }
            None => Err(()),
        }
    }

    pub fn try_decrease_to_positive(&mut self, delta: i32) -> Result<(), ()> {
        match self.0.checked_sub(delta) {
            Some(new) if new >= 0 => {
                self.0 = new;
                Ok(())
            }
            _ => Err(()),
        }
    }

    /// Creates a new `WindowSize` with the given initial size.
    pub fn new(size: i32) -> WindowSize {
        WindowSize(size)
    }
    /// Returns the current size of the window.
    ///
    /// The size is actually allowed to become negative (for instance if the peer changes its
    /// intial window size in the settings); therefore, the return is an `i32`.
    pub fn size(&self) -> i32 {
        self.0
    }
}

/// An enum representing the two possible HTTP schemes.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum HttpScheme {
    /// The variant corresponding to `http://`
    Http,
    /// The variant corresponding to `https://`
    Https,
}

impl HttpScheme {
    /// Returns a byte string representing the scheme.
    #[inline]
    pub fn as_bytes(&self) -> &'static [u8] {
        match *self {
            HttpScheme::Http => b"http",
            HttpScheme::Https => b"https",
        }
    }
}

#[cfg(test)]
pub mod tests;
<commit_msg>Impl Display for WindowSize<commit_after>//! The module implements the framing layer of HTTP/2 and exposes an API for using it.

use std::u32;
use std::fmt;

use self::frame::settings::HttpSettings;

pub mod frame;
pub mod connection;
pub mod session;
pub mod header;

// 6.5.2 Defined SETTINGS Parameters
pub const DEFAULT_SETTINGS: HttpSettings = HttpSettings {
    header_table_size: 4_096,
    enable_push: true,
    max_concurrent_streams: u32::MAX,
    initial_window_size: 65_535,
    max_frame_size: 16_384,
    max_header_list_size: u32::MAX,
};

/// An alias for the type that represents the ID of an HTTP/2 stream
pub type StreamId = u32;

/// A set of protocol names that the library should use to indicate that HTTP/2
/// is supported during protocol negotiation (NPN or ALPN).
/// We include some of the drafts' protocol names, since there is basically no
/// difference for all intents and purposes (and some servers out there still
/// only officially advertise draft support).
/// TODO: Eventually only use "h2".
pub const ALPN_PROTOCOLS: &'static [&'static [u8]] = &[b"h2", b"h2-16", b"h2-15", b"h2-14"];

/// A sender MUST NOT allow a flow-control window to exceed 231-1 octets. If a sender receives
/// a WINDOW_UPDATE that causes a flow-control window to exceed this maximum,
/// it MUST terminate either the stream or the connection, as appropriate. For streams,
/// the sender sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR; for the connection,
/// a GOAWAY frame with an error code of FLOW_CONTROL_ERROR is sent.
pub const MAX_WINDOW_SIZE: u32 = 0x7fffffff;

// 6.9 WINDOW_UPDATE
/// The payload of a WINDOW_UPDATE frame is one reserved bit plus an unsigned 31-bit integer
/// indicating the number of octets that the sender can transmit in addition to the existing
/// flow-control window. The legal range for the increment to the flow-control window
/// is 1 to 231-1 (2,147,483,647) octets.
pub const MAX_WINDOW_SIZE_INC: u32 = 0x7fffffff;

/// The struct represents the size of a flow control window.
///
/// It exposes methods that allow the manipulation of window sizes, such that they can never
/// overflow the spec-mandated upper bound.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct WindowSize(pub i32);
impl WindowSize {
    /// Tries to increase the window size by the given delta. If the WindowSize would overflow the
    /// maximum allowed value (2^31 - 1), returns an error case. If the increase succeeds, returns
    /// `Ok`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use httpbis::solicit::WindowSize;
    ///
    /// let mut window_size = WindowSize::new(65_535);
    /// assert_eq!(window_size.size(), 65_535);
    /// // An increase within the bounds...
    /// assert!(window_size.try_increase(100).is_ok());
    /// assert_eq!(window_size.size(), 65_635);
    /// // An increase that would overflow
    /// assert!(window_size.try_increase(0x7fffffff).is_err());
    /// assert_eq!(window_size.size(), 65_635);
    /// ```
    pub fn try_increase(&mut self, delta: u32) -> Result<(), ()> {
        // Someone's provided a delta that would definitely overflow the window size.
        if delta > MAX_WINDOW_SIZE_INC || delta == 0 {
            return Err(());
        }
        // Now it is safe to cast the delta to the `i32`.
        match self.0.checked_add(delta as i32) {
            None => {
                // When the add overflows, we will have went over the maximum allowed size of the
                // window size...
                Err(())
            }
            Some(next_val) => {
                // The addition didn't overflow, so the next window size is in the range allowed by
                // the spec.
                self.0 = next_val;
                Ok(())
            }
        }
    }

    /// Tries to decrease the size of the window by the given delta.
    ///
    /// There are situations where the window size should legitimately be allowed to become
    /// negative, so the only situation where the result is an error is if the window size would
    /// underflow, as this would definitely cause the peers to lose sync.
    ///
    /// # Example
    ///
    /// ```rust
    /// use httpbis::solicit::WindowSize;
    ///
    /// let mut window_size = WindowSize::new(65_535);
    /// assert_eq!(window_size.size(), 65_535);
    /// // A decrease...
    /// assert!(window_size.try_decrease(100).is_ok());
    /// assert_eq!(window_size.size(), 65_435);
    /// // A decrease that does not underflow
    /// assert!(window_size.try_decrease(0x7fffffff).is_ok());
    /// assert_eq!(window_size.size(), -2147418212);
    /// // A decrease that *would* underflow
    /// assert!(window_size.try_decrease(0x7fffffff).is_err());
    /// assert_eq!(window_size.size(), -2147418212);
    /// ```
    pub fn try_decrease(&mut self, delta: i32) -> Result<(), ()> {
        match self.0.checked_sub(delta) {
            Some(new) => {
                self.0 = new;
                Ok(())
            }
            None => Err(()),
        }
    }

    pub fn try_decrease_to_positive(&mut self, delta: i32) -> Result<(), ()> {
        match self.0.checked_sub(delta) {
            Some(new) if new >= 0 => {
                self.0 = new;
                Ok(())
            }
            _ => Err(()),
        }
    }

    /// Creates a new `WindowSize` with the given initial size.
    pub fn new(size: i32) -> WindowSize {
        WindowSize(size)
    }
    /// Returns the current size of the window.
    ///
    /// The size is actually allowed to become negative (for instance if the peer changes its
    /// intial window size in the settings); therefore, the return is an `i32`.
    pub fn size(&self) -> i32 {
        self.0
    }
}

impl fmt::Display for WindowSize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// An enum representing the two possible HTTP schemes.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum HttpScheme {
    /// The variant corresponding to `http://`
    Http,
    /// The variant corresponding to `https://`
    Https,
}

impl HttpScheme {
    /// Returns a byte string representing the scheme.
    #[inline]
    pub fn as_bytes(&self) -> &'static [u8] {
        match *self {
            HttpScheme::Http => b"http",
            HttpScheme::Https => b"https",
        }
    }
}

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


<commit_before>use libc;
use std::os::unix::io::RawFd;
use {Errno, Result};

libc_bitflags! {
    flags EfdFlags: libc::c_int {
        const EFD_CLOEXEC, // Since Linux 2.6.27
        const EFD_NONBLOCK, // Since Linux 2.6.27
        const EFD_SEMAPHORE, // Since Linux 2.6.30
    }
}

pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
    let res = unsafe { libc::eventfd(initval, flags.bits()) };

    Errno::result(res).map(|r| r as RawFd)
}
<commit_msg>Auto merge of #492 - domsj:fix-eventfd-feature, r=fiveop<commit_after>use libc;
use std::os::unix::io::RawFd;
use {Errno, Result};

libc_bitflags! {
    flags EfdFlags: libc::c_int {
        EFD_CLOEXEC, // Since Linux 2.6.27
        EFD_NONBLOCK, // Since Linux 2.6.27
        EFD_SEMAPHORE, // Since Linux 2.6.30
    }
}

pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
    let res = unsafe { libc::eventfd(initval, flags.bits()) };

    Errno::result(res).map(|r| r as RawFd)
}
<|endoftext|>


<commit_before>//! This module implements several error types and traits.
//!
//! The suggested usage in returned results is as follows:
//!
//! * The concrete `util::concrete::Error` type (re-exported as `util::Error`) is great for code
//!   that is not part of the request/response lifecycle.  It avoids pulling in the unnecessary
//!   infrastructure to convert errors into a user facing JSON responses (relative to `AppError`).
//! * `diesel::QueryResult` - There is a lot of code that only deals with query errors.  If only
//!   one type of error is possible in a function, using that specific error is preferable to the
//!   more general `util::Error`.  This is especially common in model code.
//! * `util::errors::AppResult` - Some failures should be converted into user facing JSON
//!   responses.  This error type is more dynamic and is box allocated.  Low-level errors are
//!   typically not converted to user facing errors and most usage is within the models,
//!   controllers, and middleware layers.

use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

use chrono::NaiveDateTime;
use diesel::result::Error as DieselError;

use crate::util::AppResponse;

mod json;

pub use json::TOKEN_FORMAT_ERROR;
pub(crate) use json::{InsecurelyGeneratedTokenRevoked, NotFound, ReadOnlyMode, TooManyRequests};

/// Returns an error with status 200 and the provided description as JSON
///
/// This is for backwards compatibility with cargo endpoints.  For all other
/// endpoints, use helpers like `bad_request` or `server_error` which set a
/// correct status code.
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::Ok(error.to_string()))
}

// The following are intended to be used for errors being sent back to the Ember
// frontend, not to cargo as cargo does not handle non-200 response codes well
// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
// non-200 response codes for its stores to work properly.

/// Return an error with status 400 and the provided description as JSON
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::BadRequest(error.to_string()))
}

pub fn account_locked(reason: &str, until: Option<NaiveDateTime>) -> Box<dyn AppError> {
    Box::new(json::AccountLocked {
        reason: reason.to_string(),
        until,
    })
}

pub fn forbidden() -> Box<dyn AppError> {
    Box::new(json::Forbidden)
}

pub fn not_found() -> Box<dyn AppError> {
    Box::new(json::NotFound)
}

/// Returns an error with status 500 and the provided description as JSON
pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::ServerError(error.to_string()))
}

// =============================================================================
// AppError trait

pub trait AppError: Send + fmt::Display + fmt::Debug + 'static {
    /// Generate an HTTP response for the error
    ///
    /// If none is returned, the error will bubble up the middleware stack
    /// where it is eventually logged and turned into a status 500 response.
    fn response(&self) -> Option<AppResponse>;

    /// The cause of an error response
    ///
    /// If present, an error provided to the `LogRequests` middleware.
    ///
    /// This is intended for use with the `ChainError` trait, where a user facing
    /// error may wrap an internal error we still want to log.
    fn cause(&self) -> Option<&dyn AppError> {
        None
    }

    fn get_type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }

    fn chain<E>(self, error: E) -> Box<dyn AppError>
    where
        Self: Sized,
        E: AppError,
    {
        Box::new(ChainedError {
            error,
            cause: Box::new(self),
        })
    }
}

impl dyn AppError {
    pub fn is<T: Any>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
        match err.downcast_ref() {
            Some(DieselError::NotFound) => Some(not_found()),
            Some(DieselError::DatabaseError(_, info))
                if info.message().ends_with("read-only transaction") =>
            {
                Some(Box::new(ReadOnlyMode))
            }
            _ => None,
        }
    }
}

impl AppError for Box<dyn AppError> {
    fn response(&self) -> Option<AppResponse> {
        (**self).response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        (**self).cause()
    }

    fn get_type_id(&self) -> TypeId {
        (**self).get_type_id()
    }
}

pub type AppResult<T> = Result<T, Box<dyn AppError>>;

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> AppResult<T>
    where
        E: AppError,
        F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<dyn AppError>,
}

impl<T, E: AppError> ChainError<T> for Result<T, E> {
    fn chain_error<E2, C>(self, callback: C) -> AppResult<T>
    where
        E2: AppError,
        C: FnOnce() -> E2,
    {
        self.map_err(move |err| err.chain(callback()))
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: AppError> AppError for ChainedError<E> {
    fn response(&self) -> Option<AppResponse> {
        self.error.response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        Some(&*self.cause)
    }
}

impl<E: AppError> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} caused by {}", self.error, self.cause)
    }
}

// =============================================================================
// Error impls

impl<E: Error + Send + 'static> AppError for E {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

impl<E: Error + Send + 'static> From<E> for Box<dyn AppError> {
    fn from(err: E) -> Box<dyn AppError> {
        AppError::try_convert(&err).unwrap_or_else(|| Box::new(err))
    }
}
// =============================================================================
// Internal error for use with `chain_error`

#[derive(Debug)]
struct InternalAppError {
    description: String,
}

impl fmt::Display for InternalAppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppError {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

#[derive(Debug)]
struct InternalAppErrorStatic {
    description: &'static str,
}

impl fmt::Display for InternalAppErrorStatic {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppErrorStatic {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(InternalAppError {
        description: error.to_string(),
    })
}

#[derive(Debug)]
struct AppErrToStdErr(pub Box<dyn AppError>);

impl Error for AppErrToStdErr {}

impl fmt::Display for AppErrToStdErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
    Box::new(AppErrToStdErr(e))
}

#[test]
fn chain_error_internal() {
    assert_eq!(
        None::<()>
            .chain_error(|| internal("inner"))
            .chain_error(|| internal("middle"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by middle caused by inner"
    );
    assert_eq!(
        Err::<(), _>(internal("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );

    // Don't do this, the user will see a generic 500 error instead of the intended message
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );
    assert_eq!(
        Err::<(), _>(forbidden())
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by must be logged in to perform that action"
    );
}

#[test]
fn chain_error_user_facing() {
    // Do this rarely, the user will only see the outer error
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner" // never logged
    );

    // The outer error is sent as a response to the client.
    // The inner error never bubbles up to the logging middleware
    assert_eq!(
        Err::<(), _>(std::io::Error::from(std::io::ErrorKind::PermissionDenied))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by permission denied" // never logged
    );
}
<commit_msg>util/errors: Fix "trait objects without an explicit `dyn`" deprecation warning<commit_after>//! This module implements several error types and traits.
//!
//! The suggested usage in returned results is as follows:
//!
//! * The concrete `util::concrete::Error` type (re-exported as `util::Error`) is great for code
//!   that is not part of the request/response lifecycle.  It avoids pulling in the unnecessary
//!   infrastructure to convert errors into a user facing JSON responses (relative to `AppError`).
//! * `diesel::QueryResult` - There is a lot of code that only deals with query errors.  If only
//!   one type of error is possible in a function, using that specific error is preferable to the
//!   more general `util::Error`.  This is especially common in model code.
//! * `util::errors::AppResult` - Some failures should be converted into user facing JSON
//!   responses.  This error type is more dynamic and is box allocated.  Low-level errors are
//!   typically not converted to user facing errors and most usage is within the models,
//!   controllers, and middleware layers.

use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

use chrono::NaiveDateTime;
use diesel::result::Error as DieselError;

use crate::util::AppResponse;

mod json;

pub use json::TOKEN_FORMAT_ERROR;
pub(crate) use json::{InsecurelyGeneratedTokenRevoked, NotFound, ReadOnlyMode, TooManyRequests};

/// Returns an error with status 200 and the provided description as JSON
///
/// This is for backwards compatibility with cargo endpoints.  For all other
/// endpoints, use helpers like `bad_request` or `server_error` which set a
/// correct status code.
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::Ok(error.to_string()))
}

// The following are intended to be used for errors being sent back to the Ember
// frontend, not to cargo as cargo does not handle non-200 response codes well
// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
// non-200 response codes for its stores to work properly.

/// Return an error with status 400 and the provided description as JSON
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::BadRequest(error.to_string()))
}

pub fn account_locked(reason: &str, until: Option<NaiveDateTime>) -> Box<dyn AppError> {
    Box::new(json::AccountLocked {
        reason: reason.to_string(),
        until,
    })
}

pub fn forbidden() -> Box<dyn AppError> {
    Box::new(json::Forbidden)
}

pub fn not_found() -> Box<dyn AppError> {
    Box::new(json::NotFound)
}

/// Returns an error with status 500 and the provided description as JSON
pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::ServerError(error.to_string()))
}

// =============================================================================
// AppError trait

pub trait AppError: Send + fmt::Display + fmt::Debug + 'static {
    /// Generate an HTTP response for the error
    ///
    /// If none is returned, the error will bubble up the middleware stack
    /// where it is eventually logged and turned into a status 500 response.
    fn response(&self) -> Option<AppResponse>;

    /// The cause of an error response
    ///
    /// If present, an error provided to the `LogRequests` middleware.
    ///
    /// This is intended for use with the `ChainError` trait, where a user facing
    /// error may wrap an internal error we still want to log.
    fn cause(&self) -> Option<&dyn AppError> {
        None
    }

    fn get_type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }

    fn chain<E>(self, error: E) -> Box<dyn AppError>
    where
        Self: Sized,
        E: AppError,
    {
        Box::new(ChainedError {
            error,
            cause: Box::new(self),
        })
    }
}

impl dyn AppError {
    pub fn is<T: Any>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
        match err.downcast_ref() {
            Some(DieselError::NotFound) => Some(not_found()),
            Some(DieselError::DatabaseError(_, info))
                if info.message().ends_with("read-only transaction") =>
            {
                Some(Box::new(ReadOnlyMode))
            }
            _ => None,
        }
    }
}

impl AppError for Box<dyn AppError> {
    fn response(&self) -> Option<AppResponse> {
        (**self).response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        (**self).cause()
    }

    fn get_type_id(&self) -> TypeId {
        (**self).get_type_id()
    }
}

pub type AppResult<T> = Result<T, Box<dyn AppError>>;

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> AppResult<T>
    where
        E: AppError,
        F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<dyn AppError>,
}

impl<T, E: AppError> ChainError<T> for Result<T, E> {
    fn chain_error<E2, C>(self, callback: C) -> AppResult<T>
    where
        E2: AppError,
        C: FnOnce() -> E2,
    {
        self.map_err(move |err| err.chain(callback()))
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: AppError> AppError for ChainedError<E> {
    fn response(&self) -> Option<AppResponse> {
        self.error.response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        Some(&*self.cause)
    }
}

impl<E: AppError> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} caused by {}", self.error, self.cause)
    }
}

// =============================================================================
// Error impls

impl<E: Error + Send + 'static> AppError for E {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

impl<E: Error + Send + 'static> From<E> for Box<dyn AppError> {
    fn from(err: E) -> Box<dyn AppError> {
        <dyn AppError>::try_convert(&err).unwrap_or_else(|| Box::new(err))
    }
}
// =============================================================================
// Internal error for use with `chain_error`

#[derive(Debug)]
struct InternalAppError {
    description: String,
}

impl fmt::Display for InternalAppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppError {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

#[derive(Debug)]
struct InternalAppErrorStatic {
    description: &'static str,
}

impl fmt::Display for InternalAppErrorStatic {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppErrorStatic {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(InternalAppError {
        description: error.to_string(),
    })
}

#[derive(Debug)]
struct AppErrToStdErr(pub Box<dyn AppError>);

impl Error for AppErrToStdErr {}

impl fmt::Display for AppErrToStdErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
    Box::new(AppErrToStdErr(e))
}

#[test]
fn chain_error_internal() {
    assert_eq!(
        None::<()>
            .chain_error(|| internal("inner"))
            .chain_error(|| internal("middle"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by middle caused by inner"
    );
    assert_eq!(
        Err::<(), _>(internal("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );

    // Don't do this, the user will see a generic 500 error instead of the intended message
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );
    assert_eq!(
        Err::<(), _>(forbidden())
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by must be logged in to perform that action"
    );
}

#[test]
fn chain_error_user_facing() {
    // Do this rarely, the user will only see the outer error
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner" // never logged
    );

    // The outer error is sent as a response to the client.
    // The inner error never bubbles up to the logging middleware
    assert_eq!(
        Err::<(), _>(std::io::Error::from(std::io::ErrorKind::PermissionDenied))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by permission denied" // never logged
    );
}
<|endoftext|>